diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f18a598..e1d8e5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,6 @@ name: Shell Script Linting -on: - push: - branches: - - main - pull_request: +on: [push, pull_request] jobs: lint: diff --git a/ax.sh b/ax.sh index 04d609f..1fe1ce1 100755 --- a/ax.sh +++ b/ax.sh @@ -335,26 +335,30 @@ get_project_tree() { find . -maxdepth 3 -not -path '*/.*' | grep -vE "$ignore" | sed -e 's/[^-][^\/]*\// |/g' -e "s/|/ /g" } -# Function: Detect project language get_context() { - if [ -f "package.json" ]; then - echo "Node.js" - elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then - echo "Python" + local tags=() + + [ -f "package.json" ] && tags+=("Node.js") + ([ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || ls *.py &>/dev/null) && tags+=("Python") + ([ -f "go.mod" ] || ls *.go &>/dev/null) && tags+=("Go") + ([ -f "Cargo.toml" ] || ls *.rs &>/dev/null) && tags+=("Rust") + ([ -f "pom.xml" ] || [ -f "build.gradle" ] || ls *.java &>/dev/null) && tags+=("Java") + (ls *.cpp &>/dev/null || ls *.c &>/dev/null || ls *.h &>/dev/null) && tags+=("C/C++") + ([ -f "Gemfile" ] || ls *.rb &>/dev/null) && tags+=("Ruby") + (ls *.sh &>/dev/null) && tags+=("Shell") + (ls *.bat &>/dev/null || ls *.ps1 &>/dev/null) && tags+=("Windows-Script") + + if [ ${#tags[@]} -eq 0 ]; then + echo "General/Single-File" else - echo "General" + echo "${tags[*]}" fi } -# Function: Build the JSON payload safely using Python -# This avoids the "invalid JSON" error by properly escaping all characters create_payload() { local tree="$1" local context="$2" - # Tree and context are passed as sys.argv to avoid shell-escaping issues. - # json.dumps handles all special characters, quotes, and newlines safely — - # this prevents "invalid JSON" from raw string interpolation in the payload. python3 -c ' import json, sys @@ -363,18 +367,18 @@ context_data = sys.argv[2] model_name = sys.argv[3] system_prompt = ( - "You are a Senior DevOps Architect. Analyze the project tree and follow these strict rules: " - "IDENTIFICATION: Identify the ACTUAL project type (Node.js, Python, Go, Rust, or Shell). " - "EXCLUSION: Completely IGNORE the file ax.sh — it is the generator utility, not part of the project. " - "MINIMALISM: If the project has only shell scripts and no manifest files like package.json or requirements.txt, " + "You are a Senior DevOps Architect. Analyze the project tree and detected contexts. " + "IDENTIFICATION: Identify the ACTUAL project types. If multiple languages are present, create a hybrid workflow. " + "EXCLUSION: Completely IGNORE the file ax.sh. " + "MINIMALISM: If the project has only shell scripts and no manifest files, " "generate a workflow with exactly two steps: " "step 1 — checkout code with actions/checkout@v4; " "step 2 — a step named Lint shell scripts that runs the following command exactly: " "find . -name SINGLEQUOTE*.shSINGLEQUOTE -not -path SINGLEQUOTE*/.*SINGLEQUOTE | xargs shellcheck --severity=warning " "In the final YAML output replace every token SINGLEQUOTE with an actual single-quote character. " - "shellcheck is already installed on ubuntu-latest — do NOT add an install step. " "NO GHOST DEPENDENCIES: Never add setup steps for languages not evidenced by real source files. " - "CLEAN OUTPUT: Output ONLY raw YAML — no markdown fences, no commentary, no preamble. " + "SINGLE FILE: If only one or two standalone files exist, create a minimalist CI for them. " + "CLEAN OUTPUT: Output ONLY raw YAML — no markdown, no commentary, no preamble. " "STANDARDS: Always use runs-on: ubuntu-latest and actions/checkout@v4." ) @@ -391,6 +395,7 @@ print(json.dumps(payload)) ' "$tree" "$context" "$MODEL_NAME" } + # Function: Send request to OpenAI request_ai() { local json_payload="$1"