Skip to content

Commit 8014255

Browse files
committed
feat: native bidings
1 parent bcc708e commit 8014255

20 files changed

Lines changed: 2950 additions & 145 deletions

.github/workflows/ci.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,19 @@ jobs:
2626
with:
2727
version: latest
2828

29+
- name: Set up Rust (for native extension)
30+
uses: dtolnay/rust-toolchain@stable
31+
32+
- name: Install maturin
33+
run: |
34+
python -m pip install --upgrade pip
35+
pip install maturin
36+
37+
- name: Build native extension (editable)
38+
run: make dev-native
39+
2940
- name: Lint
3041
run: make lint
3142

3243
- name: Test
3344
run: make test
34-
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Build Native Wheels (codex-native)
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch: {}
8+
9+
permissions:
10+
contents: read
11+
id-token: write
12+
13+
jobs:
14+
build:
15+
continue-on-error: ${{ matrix.allow-failure == true }}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
os: [ubuntu-latest, macos-14, windows-latest]
20+
python-version: ['3.12', '3.13']
21+
include:
22+
- os: ubuntu-latest
23+
python-version: '3.14'
24+
allow-failure: true
25+
runs-on: ${{ matrix.os }}
26+
steps:
27+
- name: Checkout repository
28+
uses: actions/checkout@v4
29+
30+
- name: Set up Rust
31+
uses: dtolnay/rust-toolchain@stable
32+
33+
- name: Set up Python
34+
uses: actions/setup-python@v5
35+
with:
36+
python-version: ${{ matrix.python-version }}
37+
38+
- name: Install maturin
39+
run: |
40+
python -m pip install --upgrade pip
41+
pip install maturin
42+
43+
- name: Build wheels with maturin
44+
env:
45+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
46+
run: |
47+
maturin build -m crates/codex_native/Cargo.toml --release --interpreter python
48+
49+
- name: Upload wheels
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: wheels-${{ matrix.os }}-${{ matrix.python-version }}
53+
path: crates/codex_native/target/wheels/*.whl
54+
55+
publish:
56+
needs: build
57+
runs-on: ubuntu-latest
58+
steps:
59+
- name: Download all wheels
60+
uses: actions/download-artifact@v4
61+
with:
62+
path: dist
63+
64+
- name: Publish to PyPI (Trusted Publishing)
65+
uses: pypa/gh-action-pypi-publish@release/v1
66+
with:
67+
packages-dir: dist
68+
skip-existing: true

.github/workflows/publish.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77

88
permissions:
99
contents: read
10+
id-token: write
1011

1112
jobs:
1213
build-and-publish:
@@ -28,7 +29,5 @@ jobs:
2829
- name: Build distribution
2930
run: uv build
3031

31-
- name: Publish to PyPI
32-
env:
33-
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
34-
run: uv publish --token "$PYPI_API_TOKEN"
32+
- name: Publish to PyPI (Trusted Publishing)
33+
run: uv publish --trusted-publishing=always

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,32 @@ coverage.xml
4242

4343
# uv
4444
.uv/
45+
uv.lock
4546

47+
# Generated artifacts
48+
# Generated artifacts
49+
.generated/
50+
codex-proj/
51+
.githooks/
52+
test/
53+
tests/
54+
55+
# Ignore new markdown files by default
56+
*.md
57+
58+
# Rust build outputs
59+
target/
60+
crates/**/target/
61+
crates/**/Cargo.lock
62+
63+
# Local environment files
64+
.env
65+
.env.*
66+
/.idea/inspectionProfiles/profiles_settings.xml
67+
/.idea/inspectionProfiles/Project_Default.xml
68+
/.idea/.gitignore
69+
/.idea/codex-python.iml
70+
/.idea/misc.xml
71+
/.idea/modules.xml
72+
/.idea/ruff.xml
73+
/.idea/vcs.xml

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
66

7+
## [0.2.0] - 2025-09-10
8+
### Added
9+
- Fully-typed Pydantic config `CodexConfig` mirroring Rust `ConfigOverrides`.
10+
- Native helper `codex.native.preview_config()` to inspect effective configuration.
11+
- Export `EventMsg` at `codex.EventMsg` for convenience.
12+
13+
### Changed
14+
- Consolidated on native bindings; removed subprocess CLI wrapper from public path.
15+
- Regenerated protocol models with `extra='allow'` and placed `model_config` at class end.
16+
- Event envelope now uses typed union: `Event.msg: EventMsg`.
17+
18+
### CI/Build
19+
- `make gen-protocol` prefers `codex generate-ts --out` with cargo fallback.
20+
- Native wheels CI builds for CPython 3.12/3.13 (attempts 3.14) with PyPI Trusted Publishing.
21+
22+
## [0.1.1] - 2025-09-10
23+
### Added
24+
- CodexClient synchronous wrapper with defaults
25+
- Python API `run_exec` with robust error handling
26+
27+
### Changed
28+
- Switch publish workflow to PyPI Trusted Publishing (OIDC)
29+
- Docs and Makefile updates
30+
731
## [0.1.0] - 2025-09-10
832
### Added
933
- Initial project scaffold with Python 3.13+
@@ -15,3 +39,5 @@ The format is based on Keep a Changelog and this project adheres to Semantic Ver
1539
- MIT License
1640

1741
[0.1.0]: https://github.com/gersmann/codex-python/releases/tag/v0.1.0
42+
[0.1.1]: https://github.com/gersmann/codex-python/releases/tag/v0.1.1
43+
[0.2.0]: https://github.com/gersmann/codex-python/releases/tag/v0.2.0

CONTRIBUTING.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ This project is typed and ships a `py.typed` marker. Please keep public APIs typ
3636
2. Update `CHANGELOG.md`.
3737
3. Merge to `main`.
3838
4. Tag the release: `git tag -a vX.Y.Z -m "vX.Y.Z" && git push --tags`.
39-
5. GitHub Actions (publish workflow) will build and publish to PyPI on `v*` tags.
39+
5. GitHub Actions (publish workflow) will build and publish to PyPI on `v*` tags using Trusted Publishing (OIDC). No token is required.
4040

4141
## Pre-commit (optional but recommended)
4242
```
@@ -51,4 +51,3 @@ Please open an issue with reproduction steps, expected vs actual behavior, and e
5151

5252
## Code of Conduct
5353
By participating, you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md).
54-

Makefile

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ help:
77
@echo " make build - Build sdist and wheel with uv"
88
@echo " make publish - Publish to PyPI via uv (uses PYPI_API_TOKEN)"
99
@echo " make clean - Remove build artifacts"
10+
@echo " make gen-protocol - Generate Python protocol bindings from codex-rs"
1011

1112
venv:
1213
uv venv --python 3.13
@@ -16,22 +17,65 @@ fmt:
1617
uv run --group dev ruff format .
1718

1819
lint:
19-
uv run --group dev ruff format --check .
20-
uv run --group dev ruff check .
20+
uv run --group dev ruff format .
21+
uv run --group dev ruff check --fix --unsafe-fixes .
2122
uv run --group dev mypy codex
2223

2324
test:
24-
uv run --group dev pytest
25+
@bash -lc 'uv run --group dev pytest -q; ec=$$?; if [ $$ec -eq 5 ]; then echo "No tests collected"; exit 0; else exit $$ec; fi'
2526

2627
build:
2728
uv build
2829

2930
publish: build
30-
@if [ -z "$${PYPI_API_TOKEN}" ]; then \
31-
echo "PYPI_API_TOKEN is not set"; \
31+
@# Load local environment if present
32+
@set -e; \
33+
if [ -f .env ]; then set -a; . ./.env; set +a; fi; \
34+
if [ -n "$${UV_PUBLISH_TOKEN:-}" ]; then \
35+
echo "Publishing with token (UV_PUBLISH_TOKEN)"; \
36+
uv publish --token "$${UV_PUBLISH_TOKEN}"; \
37+
elif [ -n "$${PYPI_API_TOKEN:-}" ]; then \
38+
echo "Publishing with token (PYPI_API_TOKEN)"; \
39+
uv publish --token "$${PYPI_API_TOKEN}"; \
40+
elif [ -n "$${UV_PUBLISH_USERNAME:-}" ] && [ -n "$${UV_PUBLISH_PASSWORD:-}" ]; then \
41+
echo "Publishing with username/password (UV_PUBLISH_USERNAME)"; \
42+
uv publish --username "$${UV_PUBLISH_USERNAME}" --password "$${UV_PUBLISH_PASSWORD}"; \
43+
elif [ -n "$${PYPI_USERNAME:-}" ] && [ -n "$${PYPI_PASSWORD:-}" ]; then \
44+
echo "Publishing with username/password (PYPI_USERNAME)"; \
45+
uv publish --username "$${PYPI_USERNAME}" --password "$${PYPI_PASSWORD}"; \
46+
else \
47+
echo "No credentials found. Set UV_PUBLISH_TOKEN or PYPI_API_TOKEN, or UV_PUBLISH_USERNAME/UV_PUBLISH_PASSWORD (or PYPI_USERNAME/PYPI_PASSWORD)."; \
3248
exit 1; \
3349
fi
34-
uv publish --token "$$PYPI_API_TOKEN"
3550

3651
clean:
3752
rm -rf build dist *.egg-info .pytest_cache .mypy_cache .ruff_cache
53+
54+
gen-protocol:
55+
@echo "Generating TypeScript protocol types via codex-proj/codex-rs ..."
56+
@mkdir -p .generated/ts
57+
@if command -v codex >/dev/null 2>&1; then \
58+
if codex --help | grep -q "generate-ts"; then \
59+
echo "Using 'codex generate-ts'"; \
60+
codex generate-ts --out .generated/ts; \
61+
else \
62+
echo "'codex' installed but no generate-ts; falling back"; \
63+
cd codex-proj/codex-rs && cargo run -p codex-protocol-ts -- --out ../../.generated/ts; \
64+
fi; \
65+
else \
66+
echo "Using cargo run -p codex-protocol-ts"; \
67+
cd codex-proj/codex-rs && cargo run -p codex-protocol-ts -- --out ../../.generated/ts; \
68+
fi
69+
@echo "Generating Python bindings ..."
70+
@python3 scripts/generate_protocol_py.py .generated/ts
71+
@$(MAKE) fmt
72+
73+
.PHONY: build-native dev-native
74+
75+
build-native:
76+
@echo "Building native extension with maturin..."
77+
@maturin build -m crates/codex_native/Cargo.toml --release
78+
79+
dev-native:
80+
@echo "Installing native extension in dev mode..."
81+
@maturin develop -m crates/codex_native/Cargo.toml

0 commit comments

Comments
 (0)