applydir


Nameapplydir JSON
Version 0.4.0 PyPI version JSON
download
home_pageNone
SummaryUtility to apply changes to files based on AI-generated recommendations.
upload_time2025-10-06 04:49:44
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords applydir prepdir automated code changes code modification developer tools large language models llm cli code automation ai-driven development fuzzy matching
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # applydir

[![CI](https://github.com/eyecantell/applydir/actions/workflows/ci.yml/badge.svg)](https://github.com/eyecantell/applydir/actions/runs/18212548824)
[![PyPI version](https://badge.fury.io/py/applydir.svg)](https://badge.fury.io/py/applydir)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![Downloads](https://pepy.tech/badge/applydir)](https://pepy.tech/project/applydir)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Overview
`applydir` is a Python command-line tool that automates the application of LLM-generated code changes to a codebase. It processes changes specified in a JSON format, supporting actions like line replacements, file creation, and deletion. Changes are applied directly to the codebase—use Git or other version control tools (e.g., via planned `vibedir` integration) for tracking and reverting. Designed to integrate with `prepdir` (for logging and configuration) and eventually `vibedir` (for LLM communication, Git integration, and linting), `applydir` validates and applies changes with robust error handling, fuzzy matching for reliability, and resolvable file paths.

## Features
- **Supported Actions**: 
  - `replace_lines`: Replace blocks of lines in existing files (unified approach for modifications, additions, deletions).
  - `create_file`: Create new files with specified content.
  - `delete_file`: Delete files (configurable via `--no-allow-file-deletion`).
- **Reliability**: Uses fuzzy matching (Levenshtein or sequence matcher, configurable) to locate lines in existing files, with options for whitespace handling and case sensitivity.
- **JSON Input**: Processes a simple JSON structure with `file_entries`, each containing `file`, `action`, and `changes` (with `original_lines` and `changed_lines` for replacements).
- **Resolvable Paths**: Accepts relative or absolute file paths, resolved relative to `--base-dir` (default: current directory).
- **Validation**: Validates JSON structure, file paths, and non-ASCII characters (configurable via `config.yaml` or `--non-ascii-action`).
- **Configuration**: Loads defaults from `.applydir/config.yaml` or bundled `src/applydir/config.yaml` using `prepdir`'s `load_config`. Overrides via CLI or programmatic `config_override`.
- **Error Handling**: Returns structured `ApplydirError` objects with type, severity, message, and details; logged via `prepdir`'s logging system.
- **CLI Utility**: Run `applydir <input_file>` with options to customize behavior.
- **Direct Application**: Changes are applied directly to files for simplicity; track/revert via Git in workflows like `vibedir`.
- **Modular Design**: Separates JSON parsing (`ApplydirChanges`), change validation (`ApplydirFileChange`), matching (`ApplydirMatcher`), and application (`ApplydirApplicator`).

## JSON Format
Changes are provided in a JSON object with a `file_entries` array:

```json
{
  "file_entries": [
    {
      "file": "<relative_or_absolute_file_path>",
      "action": "<replace_lines|create_file|delete_file>",
      "changes": [
        {
          "original_lines": ["<lines to match in existing file (empty for create_file)>"],
          "changed_lines": ["<new lines to insert (full content for create_file)>"]
        }
      ]
    }
  ]
}
```

### Prompting to use applydir
To facilitate integration with, the `applydir_format_description` function provides a detailed prompt for LLMs to generate JSON changes compatible with `applydir`. The function includes:

- **Structure and Requirements**: Describes the JSON format, including `file_entries`, supported actions (`replace_lines`, `create_file`, `delete_file`), and validation rules (e.g., non-empty `original_lines` for `replace_lines`, resolvable file paths).
- **File Output**: Instructs the LLM to return the JSON in a file (default: `applydir_changes.json`), separate from explanatory text, aligning with LLM API practices.
- **Example JSON**: Includes a sample with multiple `replace_lines` changes, a `create_file` action, and a `delete_file` action.
- **Customization**: Accepts a `filename` parameter to specify the output file name.

This function ensures LLMs generate valid JSON for `applydir`, supporting LLM communication. See the [example JSON](#json-format) for reference.

### Example Cases
- **Modification (replace_lines)**: Replace a block in `src/main.py`:
  ```json
  {
    "file_entries": [
      {
        "file": "src/main.py",
        "action": "replace_lines",
        "changes": [
          {"original_lines": ["print('Hello')"], "changed_lines": ["print('Hello World')"]}
        ]
      }
    ]
  }
  ```
- **Addition**: Match a block and replace with additional lines.
- **Deletion**: Match a block and replace with fewer lines, or use `delete_file` for entire files.
- **Creation (create_file)**: Create `src/new.py` with content:
  ```json
  {
    "file_entries": [
      {
        "file": "src/new.py",
        "action": "create_file",
        "changes": [
          {"original_lines": [], "changed_lines": ["def new_func():", "    pass"]}
        ]
      }
    ]
  }
  ```
- **Deletion (delete_file)**: Delete `src/old.py`:
  ```json
  {
    "file_entries": [
      {
        "file": "src/old.py",
        "action": "delete_file",
        "changes": []
      }
    ]
  }
  ```

## Installation
```bash
pip install applydir
```

## Usage
### CLI
Run the `applydir` utility to apply changes from a JSON file:
```bash
applydir changes.json [--base-dir <path>] [--no-allow-file-deletion] [--non-ascii-action {error,warning,ignore}] [--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
```
- `changes.json`: Path to the JSON file containing changes.
- `--base-dir`: Base directory for file paths (default: `.`).
- `--no-allow-file-deletion`: Disable file deletions (overrides config).
- `--non-ascii-action`: Handle non-ASCII characters (`error`, `warning`, or `ignore`; overrides config).
- `--log-level`: Set logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`).

### Example
```bash
applydir changes.json --base-dir /path/to/project --no-allow-file-deletion --non-ascii-action=error --log-level=DEBUG
```

### Programmatic
```python
from applydir import ApplydirApplicator, ApplydirChanges, ApplydirMatcher
from applydir.applydir_error import ApplydirError, ErrorSeverity
import logging
from prepdir import configure_logging

logger = logging.getLogger("applydir")
configure_logging(logger, level="INFO")

changes_json = {
    "file_entries": [
        {
            "file": "src/main.py",
            "action": "replace_lines",
            "changes": [{"original_lines": ["print('Hello')"], "changed_lines": ["print('Hello World')"]}]
        }
    ]
}
changes = ApplydirChanges(file_entries=changes_json["file_entries"])
matcher = ApplydirMatcher(similarity_threshold=0.95)
applicator = ApplydirApplicator(
    base_dir="/path/to/project",
    changes=changes,
    matcher=matcher,
    logger=logger,
    config_override={"allow_file_deletion": False, "validation": {"non_ascii": {"default": "error"}}}
)
errors = applicator.apply_changes()
has_errors = False
for error in errors:
    log_level = (
        logging.INFO if error.severity == ErrorSeverity.INFO
        else logging.WARNING if error.severity == ErrorSeverity.WARNING
        else logging.ERROR
    )
    logger.log(log_level, f"{error.message}: {error.details}")
    if error.severity in [ErrorSeverity.ERROR, ErrorSeverity.WARNING]:
        has_errors = True
if not has_errors:
    logger.info("Changes applied successfully")
```

## Configuration
`applydir` loads defaults from `.applydir/config.yaml` or bundled `src/applydir/config.yaml` using `prepdir`'s `load_config`. CLI options or programmatic `config_override` can override settings.

Example `config.yaml`:
```yaml
validation:
  non_ascii:
    default: warning
    rules:
      - extensions: [".py", ".js"]
        action: error
      - extensions: [".md", ".markdown"]
        action: ignore
      - extensions: [".json", ".yaml"]
        action: warning
allow_file_deletion: true
matching:
  whitespace:
    default: collapse
  similarity:
    default: 0.95
  similarity_metric:
    default: levenshtein
  use_fuzzy:
    default: true
```

- `validation.non_ascii`: Controls non-ASCII handling (default, rules by extension).
- `allow_file_deletion`: Enables/disables deletions (default: true).
- `matching`: Settings for `ApplydirMatcher` (whitespace, similarity threshold/metric, fuzzy matching).

Logging level is set via CLI `--log-level` or programmatically.

## Error Format
Errors and warnings are returned as a list of `ApplydirError` objects and logged:

```json
[
  {
    "change": null,
    "error_type": "json_structure",
    "severity": "error",
    "message": "Invalid JSON structure",
    "details": {}
  },
  {
    "change": null,
    "error_type": "file_not_found",
    "severity": "error",
    "message": "File does not exist for deletion",
    "details": {"file": "/path/to/missing.py"}
  },
  {
    "change": null,
    "error_type": "file_changes_successful",
    "severity": "info",
    "message": "All changes to file applied successfully",
    "details": {"file": "/path/to/main.py", "actions": ["replace_lines"], "change_count": 1}
  }
]
```

## Error Types
- `json_structure`: Invalid JSON (e.g., missing `file_entries`).
- `invalid_change`: Invalid change format or validation failure.
- `file_not_found`: File missing for modification/deletion.
- `file_already_exists`: File exists for creation.
- `no_match`: No matching lines found.
- `multiple_matches`: Multiple matches for lines.
- `permission_denied`: Deletion disabled.
- `file_system`: File operation failure.
- `file_changes_successful`: Successful application (info level).

## Class Structure
1. **ApplydirError**:
   - Represents errors/warnings.
   - Attributes: `change: Optional[Any]`, `error_type: ErrorType`, `severity: ErrorSeverity`, `message: str`, `details: Dict`.

2. **ApplydirChanges**:
   - Parses/validates JSON `file_entries`.
   - Methods: `validate_changes(base_dir: str, config: Dict) -> List[ApplydirError]`.

3. **ApplydirFileChange**:
   - Represents a single change.
   - Methods: `from_file_entry(file_path: Path, action: str, change_dict: Optional[Dict]) -> ApplydirFileChange`, `validate_change(config: Dict) -> List[ApplydirError]`.

4. **ApplydirMatcher**:
   - Matches lines with fuzzy options.
   - Methods: `match(file_content: List[str], change: ApplydirFileChange) -> Tuple[Optional[Dict], List[ApplydirError]]`.

5. **ApplydirApplicator**:
   - Applies changes.
   - Methods: `apply_changes() -> List[ApplydirError]`, supports create/replace/delete.

## Workflow
1. **Input**: Run `applydir <input_file>` with JSON changes.
2. **Parsing**: Load JSON, check `file_entries`, create `ApplydirChanges`.
3. **Validation**: Validate structure, paths, non-ASCII via `validate_changes`.
4. **Application**: Use `ApplydirApplicator` to match lines (`ApplydirMatcher`) and apply changes directly.
5. **Output**: Log errors/successes, return exit code (0 success, 1 failure).

## Planned Features
- **vibedir Integration**: LLM prompting, Git commits/rollbacks, linting.
- **Extended Actions**: More action types if needed.
- **Additional Validation**: Syntax/linting checks.

## Dependencies
- **prepdir**: For `load_config` (configuration) and `configure_logging` (logging).
- **Pydantic**: For model validation (e.g., `ApplydirError`, `ApplydirChanges`).
- **dynaconf**: For configuration merging.
- **difflib** (standard library): For sequence matcher in fuzzy matching.

## Python Best Practices
- PEP 8 compliant naming and structure.
- Type hints and Pydantic for safety.
- Modular classes for testability.
- Logging via `prepdir`.

## Edge Cases
- Invalid JSON/missing `file_entries`: Logged and exit 1.
- Non-existent files for replace/delete: `file_not_found` error.
- Existing files for create: `file_already_exists` error.
- Non-ASCII: Handled per config/CLI.
- Multiple/no matches: `multiple_matches` or `no_match` errors.

## Testing
- Tests in `tests/test_main.py` cover CLI execution, validation, errors, and options.
- Run: `pdm run pytest tests/test_main.py`

## Next Steps
- Implement `vibedir` for full workflow.
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "applydir",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "applydir, prepdir, automated code changes, code modification, developer tools, large language models, llm, cli, code automation, ai-driven development, fuzzy matching",
    "author": null,
    "author_email": "eyecantell <paul@pneuma.solutions>",
    "download_url": "https://files.pythonhosted.org/packages/83/6f/f48d2a07f95500c8cdc520b8d354ac9105580e832c3979960a5726a15e99/applydir-0.4.0.tar.gz",
    "platform": null,
    "description": "# applydir\n\n[![CI](https://github.com/eyecantell/applydir/actions/workflows/ci.yml/badge.svg)](https://github.com/eyecantell/applydir/actions/runs/18212548824)\n[![PyPI version](https://badge.fury.io/py/applydir.svg)](https://badge.fury.io/py/applydir)\n[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)\n[![Downloads](https://pepy.tech/badge/applydir)](https://pepy.tech/project/applydir)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Overview\n`applydir` is a Python command-line tool that automates the application of LLM-generated code changes to a codebase. It processes changes specified in a JSON format, supporting actions like line replacements, file creation, and deletion. Changes are applied directly to the codebase\u2014use Git or other version control tools (e.g., via planned `vibedir` integration) for tracking and reverting. Designed to integrate with `prepdir` (for logging and configuration) and eventually `vibedir` (for LLM communication, Git integration, and linting), `applydir` validates and applies changes with robust error handling, fuzzy matching for reliability, and resolvable file paths.\n\n## Features\n- **Supported Actions**: \n  - `replace_lines`: Replace blocks of lines in existing files (unified approach for modifications, additions, deletions).\n  - `create_file`: Create new files with specified content.\n  - `delete_file`: Delete files (configurable via `--no-allow-file-deletion`).\n- **Reliability**: Uses fuzzy matching (Levenshtein or sequence matcher, configurable) to locate lines in existing files, with options for whitespace handling and case sensitivity.\n- **JSON Input**: Processes a simple JSON structure with `file_entries`, each containing `file`, `action`, and `changes` (with `original_lines` and `changed_lines` for replacements).\n- **Resolvable Paths**: Accepts relative or absolute file paths, resolved relative to `--base-dir` (default: current directory).\n- **Validation**: Validates JSON structure, file paths, and non-ASCII characters (configurable via `config.yaml` or `--non-ascii-action`).\n- **Configuration**: Loads defaults from `.applydir/config.yaml` or bundled `src/applydir/config.yaml` using `prepdir`'s `load_config`. Overrides via CLI or programmatic `config_override`.\n- **Error Handling**: Returns structured `ApplydirError` objects with type, severity, message, and details; logged via `prepdir`'s logging system.\n- **CLI Utility**: Run `applydir <input_file>` with options to customize behavior.\n- **Direct Application**: Changes are applied directly to files for simplicity; track/revert via Git in workflows like `vibedir`.\n- **Modular Design**: Separates JSON parsing (`ApplydirChanges`), change validation (`ApplydirFileChange`), matching (`ApplydirMatcher`), and application (`ApplydirApplicator`).\n\n## JSON Format\nChanges are provided in a JSON object with a `file_entries` array:\n\n```json\n{\n  \"file_entries\": [\n    {\n      \"file\": \"<relative_or_absolute_file_path>\",\n      \"action\": \"<replace_lines|create_file|delete_file>\",\n      \"changes\": [\n        {\n          \"original_lines\": [\"<lines to match in existing file (empty for create_file)>\"],\n          \"changed_lines\": [\"<new lines to insert (full content for create_file)>\"]\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Prompting to use applydir\nTo facilitate integration with, the `applydir_format_description` function provides a detailed prompt for LLMs to generate JSON changes compatible with `applydir`. The function includes:\n\n- **Structure and Requirements**: Describes the JSON format, including `file_entries`, supported actions (`replace_lines`, `create_file`, `delete_file`), and validation rules (e.g., non-empty `original_lines` for `replace_lines`, resolvable file paths).\n- **File Output**: Instructs the LLM to return the JSON in a file (default: `applydir_changes.json`), separate from explanatory text, aligning with LLM API practices.\n- **Example JSON**: Includes a sample with multiple `replace_lines` changes, a `create_file` action, and a `delete_file` action.\n- **Customization**: Accepts a `filename` parameter to specify the output file name.\n\nThis function ensures LLMs generate valid JSON for `applydir`, supporting LLM communication. See the [example JSON](#json-format) for reference.\n\n### Example Cases\n- **Modification (replace_lines)**: Replace a block in `src/main.py`:\n  ```json\n  {\n    \"file_entries\": [\n      {\n        \"file\": \"src/main.py\",\n        \"action\": \"replace_lines\",\n        \"changes\": [\n          {\"original_lines\": [\"print('Hello')\"], \"changed_lines\": [\"print('Hello World')\"]}\n        ]\n      }\n    ]\n  }\n  ```\n- **Addition**: Match a block and replace with additional lines.\n- **Deletion**: Match a block and replace with fewer lines, or use `delete_file` for entire files.\n- **Creation (create_file)**: Create `src/new.py` with content:\n  ```json\n  {\n    \"file_entries\": [\n      {\n        \"file\": \"src/new.py\",\n        \"action\": \"create_file\",\n        \"changes\": [\n          {\"original_lines\": [], \"changed_lines\": [\"def new_func():\", \"    pass\"]}\n        ]\n      }\n    ]\n  }\n  ```\n- **Deletion (delete_file)**: Delete `src/old.py`:\n  ```json\n  {\n    \"file_entries\": [\n      {\n        \"file\": \"src/old.py\",\n        \"action\": \"delete_file\",\n        \"changes\": []\n      }\n    ]\n  }\n  ```\n\n## Installation\n```bash\npip install applydir\n```\n\n## Usage\n### CLI\nRun the `applydir` utility to apply changes from a JSON file:\n```bash\napplydir changes.json [--base-dir <path>] [--no-allow-file-deletion] [--non-ascii-action {error,warning,ignore}] [--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}]\n```\n- `changes.json`: Path to the JSON file containing changes.\n- `--base-dir`: Base directory for file paths (default: `.`).\n- `--no-allow-file-deletion`: Disable file deletions (overrides config).\n- `--non-ascii-action`: Handle non-ASCII characters (`error`, `warning`, or `ignore`; overrides config).\n- `--log-level`: Set logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`).\n\n### Example\n```bash\napplydir changes.json --base-dir /path/to/project --no-allow-file-deletion --non-ascii-action=error --log-level=DEBUG\n```\n\n### Programmatic\n```python\nfrom applydir import ApplydirApplicator, ApplydirChanges, ApplydirMatcher\nfrom applydir.applydir_error import ApplydirError, ErrorSeverity\nimport logging\nfrom prepdir import configure_logging\n\nlogger = logging.getLogger(\"applydir\")\nconfigure_logging(logger, level=\"INFO\")\n\nchanges_json = {\n    \"file_entries\": [\n        {\n            \"file\": \"src/main.py\",\n            \"action\": \"replace_lines\",\n            \"changes\": [{\"original_lines\": [\"print('Hello')\"], \"changed_lines\": [\"print('Hello World')\"]}]\n        }\n    ]\n}\nchanges = ApplydirChanges(file_entries=changes_json[\"file_entries\"])\nmatcher = ApplydirMatcher(similarity_threshold=0.95)\napplicator = ApplydirApplicator(\n    base_dir=\"/path/to/project\",\n    changes=changes,\n    matcher=matcher,\n    logger=logger,\n    config_override={\"allow_file_deletion\": False, \"validation\": {\"non_ascii\": {\"default\": \"error\"}}}\n)\nerrors = applicator.apply_changes()\nhas_errors = False\nfor error in errors:\n    log_level = (\n        logging.INFO if error.severity == ErrorSeverity.INFO\n        else logging.WARNING if error.severity == ErrorSeverity.WARNING\n        else logging.ERROR\n    )\n    logger.log(log_level, f\"{error.message}: {error.details}\")\n    if error.severity in [ErrorSeverity.ERROR, ErrorSeverity.WARNING]:\n        has_errors = True\nif not has_errors:\n    logger.info(\"Changes applied successfully\")\n```\n\n## Configuration\n`applydir` loads defaults from `.applydir/config.yaml` or bundled `src/applydir/config.yaml` using `prepdir`'s `load_config`. CLI options or programmatic `config_override` can override settings.\n\nExample `config.yaml`:\n```yaml\nvalidation:\n  non_ascii:\n    default: warning\n    rules:\n      - extensions: [\".py\", \".js\"]\n        action: error\n      - extensions: [\".md\", \".markdown\"]\n        action: ignore\n      - extensions: [\".json\", \".yaml\"]\n        action: warning\nallow_file_deletion: true\nmatching:\n  whitespace:\n    default: collapse\n  similarity:\n    default: 0.95\n  similarity_metric:\n    default: levenshtein\n  use_fuzzy:\n    default: true\n```\n\n- `validation.non_ascii`: Controls non-ASCII handling (default, rules by extension).\n- `allow_file_deletion`: Enables/disables deletions (default: true).\n- `matching`: Settings for `ApplydirMatcher` (whitespace, similarity threshold/metric, fuzzy matching).\n\nLogging level is set via CLI `--log-level` or programmatically.\n\n## Error Format\nErrors and warnings are returned as a list of `ApplydirError` objects and logged:\n\n```json\n[\n  {\n    \"change\": null,\n    \"error_type\": \"json_structure\",\n    \"severity\": \"error\",\n    \"message\": \"Invalid JSON structure\",\n    \"details\": {}\n  },\n  {\n    \"change\": null,\n    \"error_type\": \"file_not_found\",\n    \"severity\": \"error\",\n    \"message\": \"File does not exist for deletion\",\n    \"details\": {\"file\": \"/path/to/missing.py\"}\n  },\n  {\n    \"change\": null,\n    \"error_type\": \"file_changes_successful\",\n    \"severity\": \"info\",\n    \"message\": \"All changes to file applied successfully\",\n    \"details\": {\"file\": \"/path/to/main.py\", \"actions\": [\"replace_lines\"], \"change_count\": 1}\n  }\n]\n```\n\n## Error Types\n- `json_structure`: Invalid JSON (e.g., missing `file_entries`).\n- `invalid_change`: Invalid change format or validation failure.\n- `file_not_found`: File missing for modification/deletion.\n- `file_already_exists`: File exists for creation.\n- `no_match`: No matching lines found.\n- `multiple_matches`: Multiple matches for lines.\n- `permission_denied`: Deletion disabled.\n- `file_system`: File operation failure.\n- `file_changes_successful`: Successful application (info level).\n\n## Class Structure\n1. **ApplydirError**:\n   - Represents errors/warnings.\n   - Attributes: `change: Optional[Any]`, `error_type: ErrorType`, `severity: ErrorSeverity`, `message: str`, `details: Dict`.\n\n2. **ApplydirChanges**:\n   - Parses/validates JSON `file_entries`.\n   - Methods: `validate_changes(base_dir: str, config: Dict) -> List[ApplydirError]`.\n\n3. **ApplydirFileChange**:\n   - Represents a single change.\n   - Methods: `from_file_entry(file_path: Path, action: str, change_dict: Optional[Dict]) -> ApplydirFileChange`, `validate_change(config: Dict) -> List[ApplydirError]`.\n\n4. **ApplydirMatcher**:\n   - Matches lines with fuzzy options.\n   - Methods: `match(file_content: List[str], change: ApplydirFileChange) -> Tuple[Optional[Dict], List[ApplydirError]]`.\n\n5. **ApplydirApplicator**:\n   - Applies changes.\n   - Methods: `apply_changes() -> List[ApplydirError]`, supports create/replace/delete.\n\n## Workflow\n1. **Input**: Run `applydir <input_file>` with JSON changes.\n2. **Parsing**: Load JSON, check `file_entries`, create `ApplydirChanges`.\n3. **Validation**: Validate structure, paths, non-ASCII via `validate_changes`.\n4. **Application**: Use `ApplydirApplicator` to match lines (`ApplydirMatcher`) and apply changes directly.\n5. **Output**: Log errors/successes, return exit code (0 success, 1 failure).\n\n## Planned Features\n- **vibedir Integration**: LLM prompting, Git commits/rollbacks, linting.\n- **Extended Actions**: More action types if needed.\n- **Additional Validation**: Syntax/linting checks.\n\n## Dependencies\n- **prepdir**: For `load_config` (configuration) and `configure_logging` (logging).\n- **Pydantic**: For model validation (e.g., `ApplydirError`, `ApplydirChanges`).\n- **dynaconf**: For configuration merging.\n- **difflib** (standard library): For sequence matcher in fuzzy matching.\n\n## Python Best Practices\n- PEP 8 compliant naming and structure.\n- Type hints and Pydantic for safety.\n- Modular classes for testability.\n- Logging via `prepdir`.\n\n## Edge Cases\n- Invalid JSON/missing `file_entries`: Logged and exit 1.\n- Non-existent files for replace/delete: `file_not_found` error.\n- Existing files for create: `file_already_exists` error.\n- Non-ASCII: Handled per config/CLI.\n- Multiple/no matches: `multiple_matches` or `no_match` errors.\n\n## Testing\n- Tests in `tests/test_main.py` cover CLI execution, validation, errors, and options.\n- Run: `pdm run pytest tests/test_main.py`\n\n## Next Steps\n- Implement `vibedir` for full workflow.",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Utility to apply changes to files based on AI-generated recommendations.",
    "version": "0.4.0",
    "project_urls": {
        "Documentation": "https://github.com/eyecantell/applydir#readme",
        "Issues": "https://github.com/eyecantell/applydir/issues",
        "Repository": "https://github.com/eyecantell/applydir"
    },
    "split_keywords": [
        "applydir",
        " prepdir",
        " automated code changes",
        " code modification",
        " developer tools",
        " large language models",
        " llm",
        " cli",
        " code automation",
        " ai-driven development",
        " fuzzy matching"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d811bbea47fdfe875a0946fdc86f6c0203b7d7bae3cca2c61e657552e1d38fca",
                "md5": "4e160cb6f0f497f2939c0ad2be163598",
                "sha256": "abf94e1146b7fcceccc1e19bc582f2b00bd50baf68f8a19781264b9bb50439cf"
            },
            "downloads": -1,
            "filename": "applydir-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4e160cb6f0f497f2939c0ad2be163598",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 22154,
            "upload_time": "2025-10-06T04:49:43",
            "upload_time_iso_8601": "2025-10-06T04:49:43.953892Z",
            "url": "https://files.pythonhosted.org/packages/d8/11/bbea47fdfe875a0946fdc86f6c0203b7d7bae3cca2c61e657552e1d38fca/applydir-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "836ff48d2a07f95500c8cdc520b8d354ac9105580e832c3979960a5726a15e99",
                "md5": "e56e51cbc50e0a12f607703c2edc57ca",
                "sha256": "6499ae52e481b33b6bcc45770a27938af6e8d6cafbc3fd7be0bc17f2005f853a"
            },
            "downloads": -1,
            "filename": "applydir-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e56e51cbc50e0a12f607703c2edc57ca",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 35911,
            "upload_time": "2025-10-06T04:49:44",
            "upload_time_iso_8601": "2025-10-06T04:49:44.840336Z",
            "url": "https://files.pythonhosted.org/packages/83/6f/f48d2a07f95500c8cdc520b8d354ac9105580e832c3979960a5726a15e99/applydir-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-06 04:49:44",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "eyecantell",
    "github_project": "applydir#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "applydir"
}
        
Elapsed time: 4.10496s