Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Type check

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
mypy:
# `--platform` is what selects the branches mypy resolves, so all three run
# on Linux. Checking out on three runner OSes would cost three times as much
# and still check whatever platform each runner happened to be.
strategy:
fail-fast: false
matrix:
platform:
- linux
- darwin
- win32

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'

- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2

- name: Install dependencies
run: uv sync --frozen

- name: mypy --platform ${{ matrix.platform }}
run: uv run mypy --platform ${{ matrix.platform }} strix/
Comment thread
itzzdev09 marked this conversation as resolved.
Resolved
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ lint:
@echo "✅ Linting complete!"

type-check:
@echo "🔍 Type checking with mypy..."
uv run mypy strix/
@echo "🔍 Type checking with mypy (linux, darwin, win32)..."
@for platform in linux darwin win32; do \
echo " → $$platform"; \
uv run mypy --platform $$platform strix/ || exit 1; \
done
@echo "🔍 Type checking with pyright..."
uv run pyright strix/
@echo "✅ Type checking complete!"
Expand Down
36 changes: 31 additions & 5 deletions strix/config/codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import json
import logging
import secrets
import sys
import threading
import time
import urllib.parse
Expand Down Expand Up @@ -103,27 +104,52 @@ def logout() -> None:
AUTH_PATH.unlink()


# `fcntl` exists only on POSIX. Resolve it once behind a platform guard, which
# mypy narrows on every `--platform` it is asked to check, rather than at the
# call sites where it would need a per-platform ignore.
if sys.platform != "win32":
import fcntl

_HAS_FILE_LOCKING = True

def _lock_exclusive(descriptor: int) -> None:
fcntl.flock(descriptor, fcntl.LOCK_EX)

def _unlock(descriptor: int) -> None:
fcntl.flock(descriptor, fcntl.LOCK_UN)

else:
_HAS_FILE_LOCKING = False

def _lock_exclusive(descriptor: int) -> None:
"""Windows has no advisory file lock; the in-process lock still holds."""

def _unlock(descriptor: int) -> None:
"""Windows has no advisory file lock; the in-process lock still holds."""


@contextlib.contextmanager
def _refresh_guard() -> Iterator[None]:
"""Serialize token refresh within (lock) and across (flock) Strix processes,
so concurrent runs can't both spend the single-use refresh token."""
with _refresh_lock:
if not _HAS_FILE_LOCKING:
yield
return
try:
import fcntl

lock_path = AUTH_PATH.with_suffix(".lock")
lock_path.parent.mkdir(parents=True, exist_ok=True)
handle = lock_path.open("w")
except (ImportError, OSError):
except OSError:
yield
return
try:
with contextlib.suppress(OSError):
fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
_lock_exclusive(handle.fileno())
yield
finally:
with contextlib.suppress(OSError):
fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
_unlock(handle.fileno())
handle.close()


Expand Down
22 changes: 13 additions & 9 deletions strix/runtime/session_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,19 @@


def _host_identity_env() -> dict[str, str]:
# Read the platform through a local so it is not narrowed to whichever OS is
# type-checking: comparing sys.platform directly makes one of these branches
# statically dead, and which one flips between Linux and macOS.
platform_name: str = sys.platform
if platform_name != "linux":
return {}
# Bind-mount ownership only needs mapping on Linux, where the container uid
# must match the host's.
return {"STRIX_HOST_UID": str(os.getuid()), "STRIX_HOST_GID": str(os.getgid())}
# The outer guard is a real platform check, so mypy narrows it under every
# --platform it is asked about and `os.getuid` resolves where it exists.
if sys.platform != "win32":
# Inside it, read the platform through a local so it is not narrowed to
# whichever OS is type-checking: comparing sys.platform directly makes
# one of these branches statically dead, and which one flips between
# Linux and macOS.
platform_name: str = sys.platform
if platform_name == "linux":
# Bind-mount ownership only needs mapping on Linux, where the
# container uid must match the host's.
return {"STRIX_HOST_UID": str(os.getuid()), "STRIX_HOST_GID": str(os.getgid())}
return {}


def build_bind_mounts(local_sources: list[dict[str, Any]]) -> list[dict[str, Any]]:
Expand Down
Loading