diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e58cf16 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,141 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + name: Lint (Ruff) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ruff + - name: Run Ruff + run: ruff check . + + test-linux: + name: Test (Linux) + needs: lint + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest + pip install -e . + - name: Run tests + run: pytest + + test-windows: + name: Test (Windows) + needs: lint + runs-on: windows-latest + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest + pip install -e . + - name: Run tests + run: pytest + + test-macos: + name: Test (macOS) + needs: lint + runs-on: macos-latest + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest + pip install -e . + - name: Run tests + run: pytest + + build-linux: + name: Build (Linux) + needs: test-linux + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + + build-windows: + name: Build (Windows) + needs: test-windows + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + + build-macos: + name: Build (macOS) + needs: test-macos + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..2327f42 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,4 @@ +pytest +ruff +build +twine diff --git a/tests/test_ai.py b/tests/test_ai.py new file mode 100644 index 0000000..a9db973 --- /dev/null +++ b/tests/test_ai.py @@ -0,0 +1,38 @@ +from shellmind.ai import _int_env, _trim_history, _direct_shell_command, _trim_tool_output, config + +def test_int_env(monkeypatch): + monkeypatch.setenv("TEST_VAR", "10") + assert _int_env("TEST_VAR", 5, minimum=2) == 10 + + monkeypatch.setenv("TEST_VAR", "1") + assert _int_env("TEST_VAR", 5, minimum=2) == 2 + + monkeypatch.setenv("TEST_VAR", "invalid") + assert _int_env("TEST_VAR", 5, minimum=2) == 5 + + monkeypatch.delenv("TEST_VAR", raising=False) + assert _int_env("TEST_VAR", 5, minimum=2) == 5 + +def test_trim_history(): + messages = [{"role": "user", "parts": [{"text": "hello"}]}] * 10 + # config.max_history_messages is 6 by default + _trim_history(messages) + assert len(messages) <= config.max_history_messages + +def test_direct_shell_command(): + assert _direct_shell_command("!ls") == "ls" + assert _direct_shell_command("/shell echo hi") == "echo hi" + assert _direct_shell_command("/run git status") == "git status" + assert _direct_shell_command("just text") is None + +def test_trim_tool_output(): + text = "a" * 2000 + trimmed = _trim_tool_output(text) + assert "truncated" in trimmed + assert len(trimmed) < 2000 + + short_text = "hello" + assert _trim_tool_output(short_text) == "hello" + + empty_text = "" + assert _trim_tool_output(empty_text) == "(no output)"