Skip to content
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

# inkbox is mocked in the tests, so install only what they import.
- name: Install test deps
run: pip install pytest aiohttp segno

- name: Test
run: pytest -q
2 changes: 1 addition & 1 deletion inkbox_codex/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def run_doctor() -> List[Tuple[str, bool, str]]:
import inkbox # noqa: F401
checks.append(("inkbox SDK", True, "installed"))
except ImportError:
checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.7'"))
checks.append(("inkbox SDK", False, "pip install 'inkbox>=0.4.10'"))

try:
import aiohttp # noqa: F401
Expand Down
2 changes: 1 addition & 1 deletion inkbox_codex/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ async def run(self) -> None:
if not AIOHTTP_AVAILABLE:
raise RuntimeError("aiohttp is not installed; run: pip install aiohttp")
if not INKBOX_AVAILABLE:
raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.7'")
raise RuntimeError("inkbox SDK is not installed; run: pip install 'inkbox>=0.4.10'")
if not self.cfg.api_key or not self.cfg.identity:
raise RuntimeError("INKBOX_API_KEY and INKBOX_IDENTITY must be set (see README)")

Expand Down
34 changes: 32 additions & 2 deletions inkbox_codex/setup_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@

# Packages the wizard itself needs to talk to Inkbox during setup. The
# gateway's Codex CLI dependency is checked by doctor.
INKBOX_REQUIREMENTS = ("inkbox>=0.4.7", "aiohttp>=3.9")
INKBOX_REQUIREMENTS = ("inkbox>=0.4.10", "aiohttp>=3.9")
MIN_INKBOX_VERSION = (0, 4, 10)
_BRACKETED_PASTE_PATTERN = re.compile(r"\x1b\[\s*200~|\x1b\[\s*201~")

# Bundled avatar attached to the agent's Inkbox contact card during setup.
Expand Down Expand Up @@ -366,14 +367,42 @@ def _load_inkbox_symbols() -> dict[str, Any]:
}


def _inkbox_version_too_old() -> bool:
"""Return True when the installed Inkbox SDK predates MIN_INKBOX_VERSION.

Returns:
bool: True if an outdated ``inkbox`` is installed, else False.
"""
try:
import importlib.metadata as importlib_metadata

raw = importlib_metadata.version("inkbox")
except Exception:
return False
try:
# Prefer packaging when present for PEP 440-correct comparison.
from packaging.version import Version

return Version(raw) < Version(".".join(str(p) for p in MIN_INKBOX_VERSION))
except Exception:
# Fall back to a simple numeric-tuple comparison of the leading parts.
parts = tuple(int(p) for p in re.findall(r"\d+", raw)[: len(MIN_INKBOX_VERSION)])
return parts < MIN_INKBOX_VERSION


def _ensure_inkbox_sdk() -> dict[str, Any] | None:
"""Import the Inkbox SDK, offering to install it into this env if missing.

Returns:
dict[str, Any] | None: SDK symbols on success, None if unavailable.
"""
try:
return _load_inkbox_symbols()
symbols = _load_inkbox_symbols()
if not _inkbox_version_too_old():
return symbols
first_error = (
f"inkbox SDK is older than {'.'.join(str(p) for p in MIN_INKBOX_VERSION)}"
)
except Exception as exc:
first_error = exc

Expand Down Expand Up @@ -1109,6 +1138,7 @@ def _self_signup_flow(base_url: str, Inkbox: Any, InkboxAPIError: Any) -> tuple[
note_to_human=note,
agent_handle=handle,
base_url=base_url,
harness="codex",
)
break
except InkboxAPIError as exc:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Inkbox bridge for Codex — talk to your coding agent over email,
requires-python = ">=3.10"
dependencies = [
"aiohttp>=3.9",
"inkbox>=0.4.7",
"inkbox>=0.4.10",
"segno>=1.5", # terminal QR codes for the iMessage connect step
]

Expand Down
8 changes: 4 additions & 4 deletions tests/test_setup_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def test_install_command_prefers_uv_when_available(monkeypatch):
"install",
"--python",
"/tmp/venv/bin/python",
"inkbox>=0.4.7",
"inkbox>=0.4.10",
"aiohttp>=3.9",
]]

Expand All @@ -93,10 +93,10 @@ def test_install_command_falls_back_to_pip_and_ensurepip(monkeypatch):
monkeypatch.setattr(setup_wizard.shutil, "which", lambda _name: None)

assert setup_wizard._install_commands() == [
[["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.7", "aiohttp>=3.9"]],
[["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.10", "aiohttp>=3.9"]],
[
["/tmp/venv/bin/python", "-m", "ensurepip", "--upgrade"],
["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.7", "aiohttp>=3.9"],
["/tmp/venv/bin/python", "-m", "pip", "install", "inkbox>=0.4.10", "aiohttp>=3.9"],
],
]

Expand All @@ -115,7 +115,7 @@ def fail_import():
out = capsys.readouterr().out
assert "/tmp/venv/bin/python" in out
assert "uv pip install --python" in out
assert "inkbox>=0.4.7" in out
assert "inkbox>=0.4.10" in out


# ----------------------------------------------------------------------
Expand Down
Loading