diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..18162e6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,68 @@
+---
+name: Bug report
+about: File a bug report to help us improve PromptDrifter GitHub Action
+title: "[BUG]: "
+labels: bug, to triage
+assignees: ''
+type: bug
+
+---
+
+
+
+## Bug Description
+
+
+## Steps to Reproduce
+1.
+2.
+3.
+
+## Expected Behavior
+
+
+## Actual Behavior
+
+
+## Minimal Reproduction
+
+
+### GitHub Workflow
+```yaml
+# Your GitHub workflow using the action
+name: Test PromptDrifter
+on: [push]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: Code-and-Sorts/PromptDrifter-action@v0.0.1
+ with:
+ command: validate # or other command
+ files: your-config.yaml
+```
+
+### PromptDrifter Configuration
+```yaml
+# Your promptdrifter.yaml or test configuration
+```
+
+## Environment
+- **Action version**:
+- **GitHub Runner**:
+- **PromptDrifter CLI version**:
+- **Command used**:
+
+## Additional Context
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..58b3d6b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,59 @@
+---
+name: Feature request
+about: Suggest an idea or enhancement for PromptDrifter GitHub Action
+title: "[FEATURE]: "
+labels: enhancement
+assignees: ''
+type: feature
+
+---
+
+
+
+## Problem Statement
+
+
+## Proposed Solution
+
+
+## Use Case
+
+
+### Example Workflow Usage
+```yaml
+# How you would like to use this feature in a GitHub workflow
+name: Example
+on: [push]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: Code-and-Sorts/PromptDrifter-action@v0.0.1
+ with:
+ # New feature usage here
+```
+
+## Alternatives Considered
+
+
+## Additional Context
+
+
+## Implementation Notes
+
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
new file mode 100644
index 0000000..03bec0a
--- /dev/null
+++ b/.github/workflows/test.yaml
@@ -0,0 +1,220 @@
+name: Test PromptDrifter Action
+
+on:
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ test-validate:
+ runs-on: ubuntu-latest
+ name: Test Validate Command
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create test config
+ run: |
+ mkdir -p tests
+ cat > tests/sample.yaml << 'EOF'
+ version: "0.1"
+ adapters:
+ - id: test-validation
+ prompt: "Say hello"
+ expect_substring: "hello"
+ adapter:
+ - type: openai
+ model: gpt-4o-mini
+ max_tokens: 50
+ temperature: 0.7
+ tags:
+ - test
+ EOF
+
+ - name: Test validate command
+ uses: ./
+ with:
+ command: 'validate'
+ files: 'tests/sample.yaml'
+
+ test-init:
+ runs-on: ubuntu-latest
+ name: Test Init Command
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Test init command
+ uses: ./
+ with:
+ command: 'init'
+ directory: 'test-init-dir'
+
+ - name: Verify init created files
+ run: |
+ ls -la test-init-dir/
+ test -f test-init-dir/promptdrifter.yaml || echo "Config file not found"
+
+ test-input-validation:
+ runs-on: ubuntu-latest
+ name: Test Input Validation
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create test config
+ run: |
+ mkdir -p tests
+ cat > tests/minimal.yaml << 'EOF'
+ version: "0.1"
+ adapters:
+ - id: minimal-test
+ prompt: "Test"
+ expect_substring: "test"
+ adapter:
+ - type: openai
+ model: gpt-4o-mini
+ max_tokens: 10
+ tags:
+ - minimal
+ EOF
+
+ - name: Test with fake API keys (should fail gracefully)
+ uses: ./
+ continue-on-error: true
+ with:
+ command: 'run'
+ files: 'tests/minimal.yaml'
+ openai-api-key: 'fake-key-for-testing'
+ max-concurrent: '2'
+ no-cache: 'true'
+
+ - name: Test missing files input (should fail)
+ uses: ./
+ continue-on-error: true
+ with:
+ command: 'run'
+ openai-api-key: 'fake-key'
+
+ test-multiple-commands:
+ runs-on: ubuntu-latest
+ name: Test Multiple Commands
+ strategy:
+ matrix:
+ test-case:
+ - command: 'validate'
+ files: 'tests/config1.yaml tests/config2.yaml'
+ - command: 'test-drift-type'
+ drift-type: 'semantic'
+ expected: 'Hello'
+ actual: 'Hi'
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create test configs
+ run: |
+ mkdir -p tests
+ cat > tests/config1.yaml << 'EOF'
+ version: "0.1"
+ adapters:
+ - id: config1-test
+ prompt: "Test 1"
+ expect_substring: "test"
+ adapter:
+ - type: openai
+ model: gpt-4o-mini
+ max_tokens: 10
+ tags:
+ - test1
+ EOF
+ cat > tests/config2.yaml << 'EOF'
+ version: "0.1"
+ adapters:
+ - id: config2-test
+ prompt: "Test 2"
+ expect_substring: "test"
+ adapter:
+ - type: openai
+ model: gpt-4o-mini
+ max_tokens: 10
+ tags:
+ - test2
+ EOF
+
+ - name: Test command
+ uses: ./
+ continue-on-error: true
+ with:
+ command: ${{ matrix.test-case.command }}
+ files: ${{ matrix.test-case.files }}
+ drift-type: ${{ matrix.test-case.drift-type }}
+ expected: ${{ matrix.test-case.expected }}
+ actual: ${{ matrix.test-case.actual }}
+
+ test-api-key-handling:
+ runs-on: ubuntu-latest
+ name: Test API Key Environment Variables
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Create test config
+ run: |
+ mkdir -p tests
+ cat > tests/multi-provider.yaml << 'EOF'
+ version: "0.1"
+ adapters:
+ - id: openai-test
+ prompt: "Say hello"
+ expect_substring: "hello"
+ adapter:
+ - type: openai
+ model: gpt-4o-mini
+ max_tokens: 50
+ temperature: 0.7
+ tags:
+ - test
+ - id: claude-test
+ prompt: "Say hello"
+ expect_substring: "hello"
+ adapter:
+ - type: claude
+ model: claude-3-haiku
+ max_tokens: 50
+ temperature: 0.7
+ tags:
+ - test
+ EOF
+
+ - name: Test with multiple fake API keys
+ uses: ./
+ continue-on-error: true
+ with:
+ command: 'run'
+ files: 'tests/multi-provider.yaml'
+ openai-api-key: 'fake-openai-key'
+ claude-api-key: 'fake-claude-key'
+ gemini-api-key: 'fake-gemini-key'
+ no-cache: 'true'
+
+ test-error-handling:
+ runs-on: ubuntu-latest
+ name: Test Error Handling
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Test invalid command
+ uses: ./
+ continue-on-error: true
+ with:
+ command: 'invalid-command'
+ files: 'nonexistent.yaml'
+
+ - name: Test missing migrate parameters
+ uses: ./
+ continue-on-error: true
+ with:
+ command: 'migrate'
+ migrate-input: 'input.yaml'
+ # missing migrate-output should cause error
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ceb2b98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+CLAUDE.md
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..29757ea
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM python:3.11-slim
+
+LABEL "com.github.actions.name"="PromptDrifter Action"
+LABEL "com.github.actions.description"="Run PromptDrifter CLI tests in GitHub Actions"
+LABEL "com.github.actions.icon"="check-circle"
+LABEL "com.github.actions.color"="blue"
+
+RUN apt-get update && apt-get install -y \
+ git \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN pip install --no-cache-dir promptdrifter==0.0.2
+
+COPY entrypoint.sh /entrypoint.sh
+RUN chmod +x /entrypoint.sh
+
+ENTRYPOINT ["/entrypoint.sh"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 0b49a9b..bc4ac63 100644
--- a/README.md
+++ b/README.md
@@ -1,50 +1,164 @@
-# Run PromptDrifter Tests GitHub Action
+
+
+
-This GitHub Action runs your [PromptDrifter](https://github.com/CodeAndSorts/PromptDrifter) tests as part of your CI/CD workflow.
+# PromptDrifter GitHub Action
+
+Docker-based GitHub Action for running [PromptDrifter](https://github.com/Code-and-Sorts/PromptDrifter) tests in CI/CD workflows to detect prompt drift and LLM response changes.
+
+## Features
+
+- 🔍 **Drift Detection**: Catch when LLM responses change unexpectedly
+- 🚀 **CI Integration**: Fail builds when prompt drift is detected
+- 🔐 **Secure**: API keys handled via GitHub secrets
+- 📋 **Multiple Formats**: Support for various drift detection types
+- ⚡ **Fast**: Built-in caching for faster subsequent runs
+- 🌐 **Multi-Provider**: Support for OpenAI, Claude, Gemini, and more
+
+## Versioning
+
+PromptDrifter Action versions are kept in sync with the PromptDrifter CLI for clarity:
+
+- **Action v0.0.2** → **CLI v0.0.2**
+- **Action v0.0.3** → **CLI v0.0.3**
+- etc.
+
+This ensures you know exactly which CLI version you're getting and can pin to specific, tested combinations.
+
+### Version Compatibility
+
+| Action Version | CLI Version | Status |
+|----------------|-------------|------------|
+| `v0.0.2` | `0.0.2` | ✅ Current |
## Usage
-To use this action in your workflow, add the following step. This example assumes your PromptDrifter YAML test files are in a directory called `tests` and your workflow checks out your repository first.
+### Basic Example
```yaml
-name: PromptDrifter CI
-
+name: PromptDrifter Tests
on: [push, pull_request]
jobs:
- test_prompts:
+ prompt-tests:
runs-on: ubuntu-latest
steps:
- - name: Checkout repository
- uses: actions/checkout@v4
+ - uses: actions/checkout@v4
+ - uses: Code-and-Sorts/PromptDrifter-action@v0.0.2
+ with:
+ files: 'tests/promptdrifter.yaml'
+ openai-api-key: ${{ secrets.OPENAI_API_KEY }}
+```
+
+### Advanced Example
+
+```yaml
+name: Multi-Provider Prompt Tests
+on: [push, pull_request]
- - name: Run PromptDrifter tests
- uses: CodeAndSorts/promptdrifter-action@v1 # Replace with the correct action repository and version tag
+jobs:
+ prompt-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: Code-and-Sorts/PromptDrifter-action@v0.0.2
with:
- test-files: './tests/*.yaml' # Glob pattern for your test files
- # Optional inputs:
- # promptdrifter-version: '0.0.1' # Or 'main' to use the latest from git, or 'latest' for PyPI
- # config-dir: './pd_config'
- # no-cache: 'true'
- # cache-db-path: '.custom_cache.db'
- # working-directory: './sub_project'
+ files: |
+ tests/openai-tests.yaml
+ tests/claude-tests.yaml
+ tests/gemini-tests.yaml
+ openai-api-key: ${{ secrets.OPENAI_API_KEY }}
+ claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
+ gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
+ no-cache: 'false'
+ max-concurrent: '5'
+```
+
+### Initialize Configuration
+
+```yaml
+- name: Initialize PromptDrifter
+ uses: Code-and-Sorts/PromptDrifter-action@v0.0.1
+ with:
+ command: 'init'
+ directory: './prompt-tests'
+```
+
+### Validate Configuration Files
+
+```yaml
+- name: Validate Configurations
+ uses: Code-and-Sorts/PromptDrifter-action@v0.0.1
+ with:
+ command: 'validate'
+ files: 'config/*.yaml'
```
## Inputs
-| Input | Description | Required | Default |
-|-------------------------|------------------------------------------------------------------------------------------------------|----------|------------------------------|
-| `test-files` | Glob pattern for the PromptDrifter YAML test files to run (e.g., `./tests/*.yaml`, `my_tests.yaml`). | `true` | N/A |
-| `promptdrifter-version` | The version of PromptDrifter to install (e.g., `0.1.0`, `latest` for PyPI, or a git ref like `main`).| `false` | `latest` |
-| `config-dir` | Directory containing PromptDrifter configuration files. | `false` | `.` (working directory) |
-| `no-cache` | Set to `'true'` to disable PromptDrifter's response caching. | `false` | `'false'` |
-| `cache-db-path` | Path to a custom cache database file. | `false` | (PromptDrifter's default) |
-| `working-directory` | The directory from which to run the `promptdrifter` command. Useful if test files are in a sub-path. | `false` | `.` (repository root) |
+| Input | Description | Required | Default |
+|-------|-------------|----------|---------|
+| `command` | PromptDrifter command to run (`init`, `run`, `validate`, `test-drift-type`, `migrate`) | No | `run` |
+| `files` | Space-separated list of configuration files | Yes (for most commands) | - |
+| `directory` | Directory for init command | No | `.` |
+| `openai-api-key` | OpenAI API key | No | - |
+| `claude-api-key` | Anthropic Claude API key | No | - |
+| `gemini-api-key` | Google Gemini API key | No | - |
+| `qwen-api-key` | Qwen API key | No | - |
+| `grok-api-key` | Grok API key | No | - |
+| `deepseek-api-key` | DeepSeek API key | No | - |
+| `mistral-api-key` | Mistral API key | No | - |
+| `no-cache` | Disable response caching | No | `false` |
+| `max-concurrent` | Maximum concurrent tests | No | `10` |
+| `config-dir` | Directory containing config files | No | `.` |
+| `cache-db` | Path to cache database | No | - |
+| `drift-type` | Drift type for testing | No | - |
+| `expected` | Expected value for drift testing | No | - |
+| `actual` | Actual value for drift testing | No | - |
+| `migrate-input` | Input file for migration | No | - |
+| `migrate-output` | Output file for migration | No | - |
+
+## Outputs
+
+| Output | Description |
+|--------|-------------|
+| `result` | Result of the PromptDrifter execution |
+
+## Configuration
-## Contributing
+Create a `promptdrifter.yaml` file in your repository:
-Contributions are welcome! Please open an issue or pull request in this action's repository.
+```yaml
+version: "0.1"
+providers:
+ - name: openai
+ model: gpt-4o-mini
+ api_key: env:OPENAI_API_KEY
+
+tests:
+ - name: "Basic greeting test"
+ prompt: "Say hello"
+ expected: "Hello!"
+ assertion: exact_match
+```
+
+For detailed configuration options, see the [PromptDrifter documentation](https://github.com/Code-and-Sorts/PromptDrifter).
+
+## Security
+
+- Store API keys in GitHub repository secrets
+- Never commit API keys to your repository
+- API keys are passed as environment variables to Docker container
+
+## Docker Action Structure
+
+```
+├── action.yml # Action metadata (using: 'docker')
+├── Dockerfile # Python + PromptDrifter installation
+├── entrypoint.sh # Shell script that calls promptdrifter CLI
+└── README.md # This file
+```
## License
-This action is licensed under the [MIT License](LICENSE). (Or specify the chosen license)
+MIT License - see [LICENSE](LICENSE) file for details.
diff --git a/action.yaml b/action.yaml
index eaefe47..f659fcc 100644
--- a/action.yaml
+++ b/action.yaml
@@ -1,73 +1,96 @@
-name: 'Run PromptDrifter'
-description: 'Runs PromptDrifter to test prompt drift for test files.'
-author: 'CodeAndSorts'
+name: 'PromptDrifter'
+description: 'Run PromptDrifter CLI tests for LLM prompt configurations'
+author: 'Code and Sorts'
+branding:
+ icon: 'check-circle'
+ color: 'blue'
inputs:
- test-files:
- description: 'Glob pattern for the PromptDrifter YAML test files to run (e.g., ./tests/*.yaml, promptdrifter.yaml).'
+ command:
+ description: 'PromptDrifter command to run (init, run, validate, test-drift-type, migrate)'
required: true
- config-dir:
- description: 'Directory containing PromptDrifter configuration files (if any, defaults to working-directory).'
+ default: 'run'
+ files:
+ description: 'Space-separated list of configuration files to process'
+ required: false
+ directory:
+ description: 'Directory for init command'
required: false
default: '.'
+ openai-api-key:
+ description: 'OpenAI API key'
+ required: false
+ claude-api-key:
+ description: 'Claude API key'
+ required: false
+ gemini-api-key:
+ description: 'Gemini API key'
+ required: false
+ qwen-api-key:
+ description: 'Qwen API key'
+ required: false
+ grok-api-key:
+ description: 'Grok API key'
+ required: false
+ deepseek-api-key:
+ description: 'DeepSeek API key'
+ required: false
+ mistral-api-key:
+ description: 'Mistral API key'
+ required: false
no-cache:
- description: 'Disable response caching. Set to "true" to disable.'
+ description: 'Disable caching'
required: false
default: 'false'
- cache-db-path:
- description: 'Path to the cache database file (e.g., .promptdrifter.cache.db).'
+ cache-db:
+ description: 'Path to cache database'
required: false
- promptdrifter-version:
- description: 'The version of PromptDrifter to install (e.g., "0.0.1", "latest", or a git ref like "main").'
+ config-dir:
+ description: 'Configuration directory path'
required: false
- default: 'latest'
- working-directory:
- description: 'The working directory to run the tests from.'
+ max-concurrent:
+ description: 'Maximum concurrent requests'
+ required: false
+ drift-type:
+ description: 'Drift type for test-drift-type command'
+ required: false
+ expected:
+ description: 'Expected value for test-drift-type command'
+ required: false
+ actual:
+ description: 'Actual value for test-drift-type command'
+ required: false
+ migrate-input:
+ description: 'Input file for migrate command'
+ required: false
+ migrate-output:
+ description: 'Output file for migrate command'
required: false
- default: '.'
-
-runs:
- using: 'composite'
- steps:
- - name: Set up Python
- uses: actions/setup-python@v5
- with:
- python-version: '3.13'
-
- - name: Install PromptDrifter
- shell: bash
- run: |
- echo "Installing PromptDrifter version: ${{ inputs.promptdrifter-version }}"
- if [[ "${{ inputs.promptdrifter-version }}" == "latest" ]]; then
- pip install promptdrifter
- elif [[ "${{ inputs.promptdrifter-version }}" == *.*.* ]]; then # Basic check for a version number
- pip install promptdrifter==${{ inputs.promptdrifter-version }}
- else # Assume it's a git ref (branch, tag, commit)
- pip install "git+https://github.com/CodeAndSorts/PromptDrifter.git@${{ inputs.promptdrifter-version }}#egg=promptdrifter"
- fi
- # Ensure promptdrifter is in PATH if installed to user's local bin
- if [[ -d "$HOME/.local/bin" ]]; then
- echo "$HOME/.local/bin" >> $GITHUB_PATH
- fi
-
- - name: Run PromptDrifter
- shell: bash
- working-directory: ${{ inputs.working-directory }}
- run: |
- CMD="promptdrifter run"
- if [[ "${{ inputs.no-cache }}" == "true" ]]; then
- CMD="$CMD --no-cache"
- fi
- if [[ -n "${{ inputs.cache-db-path }}" ]]; then
- CMD="$CMD --cache-db '${{ inputs.cache-db-path }}'" # Quoted for safety
- fi
- if [[ -n "${{ inputs.config-dir }}" && "${{ inputs.config-dir }}" != "." ]]; then
- CMD="$CMD --config-dir '${{ inputs.config-dir }}'" # Quoted for safety
- fi
- # Add test files. Input can be a space-separated list or a single glob.
- # The shell will handle glob expansion.
- CMD="$CMD ${{ inputs.test-files }}"
+outputs:
+ result:
+ description: 'Result of the PromptDrifter execution'
- echo "Executing: $CMD"
- $CMD
+runs:
+ using: 'docker'
+ image: 'Dockerfile'
+ env:
+ INPUT_COMMAND: ${{ inputs.command }}
+ INPUT_FILES: ${{ inputs.files }}
+ INPUT_DIRECTORY: ${{ inputs.directory }}
+ INPUT_OPENAI_API_KEY: ${{ inputs.openai-api-key }}
+ INPUT_CLAUDE_API_KEY: ${{ inputs.claude-api-key }}
+ INPUT_GEMINI_API_KEY: ${{ inputs.gemini-api-key }}
+ INPUT_QWEN_API_KEY: ${{ inputs.qwen-api-key }}
+ INPUT_GROK_API_KEY: ${{ inputs.grok-api-key }}
+ INPUT_DEEPSEEK_API_KEY: ${{ inputs.deepseek-api-key }}
+ INPUT_MISTRAL_API_KEY: ${{ inputs.mistral-api-key }}
+ INPUT_NO_CACHE: ${{ inputs.no-cache }}
+ INPUT_CACHE_DB: ${{ inputs.cache-db }}
+ INPUT_CONFIG_DIR: ${{ inputs.config-dir }}
+ INPUT_MAX_CONCURRENT: ${{ inputs.max-concurrent }}
+ INPUT_DRIFT_TYPE: ${{ inputs.drift-type }}
+ INPUT_EXPECTED: ${{ inputs.expected }}
+ INPUT_ACTUAL: ${{ inputs.actual }}
+ INPUT_MIGRATE_INPUT: ${{ inputs.migrate-input }}
+ INPUT_MIGRATE_OUTPUT: ${{ inputs.migrate-output }}
diff --git a/docs/img/logo.svg b/docs/img/logo.svg
new file mode 100644
index 0000000..a46c6d6
--- /dev/null
+++ b/docs/img/logo.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 0000000..ead775e
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+set -e
+
+validate_inputs() {
+ if [[ -z "$INPUT_FILES" && "$INPUT_COMMAND" != "init" ]]; then
+ echo "Error: 'files' input is required for commands other than 'init'"
+ exit 1
+ fi
+}
+
+setup_api_keys() {
+ # Handle both underscore and hyphen formats from GitHub Actions
+ [[ -n "$INPUT_OPENAI_API_KEY" ]] && export OPENAI_API_KEY="$INPUT_OPENAI_API_KEY" || true
+ [[ -n "$INPUT_CLAUDE_API_KEY" ]] && export CLAUDE_API_KEY="$INPUT_CLAUDE_API_KEY" || true
+ [[ -n "$INPUT_GEMINI_API_KEY" ]] && export GEMINI_API_KEY="$INPUT_GEMINI_API_KEY" || true
+ [[ -n "$INPUT_QWEN_API_KEY" ]] && export QWEN_API_KEY="$INPUT_QWEN_API_KEY" || true
+ [[ -n "$INPUT_GROK_API_KEY" ]] && export GROK_API_KEY="$INPUT_GROK_API_KEY" || true
+ [[ -n "$INPUT_DEEPSEEK_API_KEY" ]] && export DEEPSEEK_API_KEY="$INPUT_DEEPSEEK_API_KEY" || true
+ [[ -n "$INPUT_MISTRAL_API_KEY" ]] && export MISTRAL_API_KEY="$INPUT_MISTRAL_API_KEY" || true
+}
+
+
+main() {
+ echo "Starting PromptDrifter Action with command: $INPUT_COMMAND"
+
+ validate_inputs
+ setup_api_keys
+
+ # Build CLI arguments more safely
+ local cli_args=()
+ case "$INPUT_COMMAND" in
+ "init")
+ cli_args+=("init")
+ [[ -n "$INPUT_DIRECTORY" ]] && cli_args+=("$INPUT_DIRECTORY")
+ ;;
+ "run")
+ cli_args+=("run")
+ read -ra FILES <<< "$INPUT_FILES"
+ cli_args+=("${FILES[@]}")
+ [[ "$INPUT_NO_CACHE" == "true" ]] && cli_args+=("--no-cache")
+ [[ -n "$INPUT_CACHE_DB" ]] && cli_args+=("--cache-db" "$INPUT_CACHE_DB")
+ [[ -n "$INPUT_CONFIG_DIR" ]] && cli_args+=("--config-dir" "$INPUT_CONFIG_DIR")
+ [[ -n "$INPUT_MAX_CONCURRENT" ]] && cli_args+=("--max-concurrent" "$INPUT_MAX_CONCURRENT")
+ ;;
+ "validate")
+ cli_args+=("validate")
+ read -ra FILES <<< "$INPUT_FILES"
+ cli_args+=("${FILES[@]}")
+ ;;
+ "test-drift-type")
+ cli_args+=("test-drift-type")
+ [[ -n "$INPUT_DRIFT_TYPE" ]] && cli_args+=("$INPUT_DRIFT_TYPE")
+ [[ -n "$INPUT_EXPECTED" ]] && cli_args+=("$INPUT_EXPECTED")
+ [[ -n "$INPUT_ACTUAL" ]] && cli_args+=("$INPUT_ACTUAL")
+ ;;
+ "migrate")
+ cli_args+=("migrate")
+ [[ -n "$INPUT_MIGRATE_INPUT" ]] && cli_args+=("$INPUT_MIGRATE_INPUT")
+ [[ -n "$INPUT_MIGRATE_OUTPUT" ]] && cli_args+=("--output" "$INPUT_MIGRATE_OUTPUT")
+ ;;
+ *)
+ echo "Error: Unknown command '$INPUT_COMMAND'"
+ echo "Available commands: init, run, validate, test-drift-type, migrate"
+ exit 1
+ ;;
+ esac
+
+ echo "Executing: promptdrifter ${cli_args[*]}"
+
+ if promptdrifter "${cli_args[@]}"; then
+ echo "PromptDrifter execution completed successfully"
+ exit 0
+ else
+ echo "PromptDrifter execution failed"
+ exit 1
+ fi
+}
+
+
+main "$@"