diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 901ee118..a3ffe59c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -340,9 +340,11 @@ jobs: "$cli_bin/codex" plugin list --json \ | python -c 'import json,sys; d=json.load(sys.stdin); p=[x for x in d.get("installed",[]) if x.get("pluginId")=="hypermnesia-mcp-codex@cortex-codex-plugins"]; assert len(p)==1, p; assert p[0]["installed"] and p[0]["enabled"]' "$cli_bin/codex" mcp list --json \ - | python -c 'import json,sys; ss=[s for s in json.load(sys.stdin) if s.get("name")=="cortex"]; assert len(ss)==1, ss; s=ss[0]; assert s["startup_timeout_sec"]==180.0, s; assert s["transport"]["command"]=="uvx", s; assert s["transport"]["env"]["CORTEX_RUNTIME"]=="cowork", s' + | python -c 'import json,sys; ss=[s for s in json.load(sys.stdin) if s.get("name")=="cortex"]; assert len(ss)==1, ss; s=ss[0]; assert s["startup_timeout_sec"]==180.0, s; assert s["transport"]["command"]=="python3", s; assert s["transport"]["env"]["CORTEX_RUNTIME"]=="cowork", s' mapfile -t plugin_command < <( - python -c 'import json; s=json.load(open("plugins/hypermnesia-mcp-codex/.mcp.json"))["mcpServers"]["cortex"]; print(s["command"]); print(*s["args"], sep="\n")' + # PLUGIN_ROOT is a literal Codex placeholder resolved by Python. + # shellcheck disable=SC2016 + python -c 'import json; from pathlib import Path; root=str(Path("plugins/hypermnesia-mcp-codex").resolve()); s=json.load(open(Path(root)/".mcp.json"))["mcpServers"]["cortex"]; print(s["command"]); print(*(arg.replace("${PLUGIN_ROOT}",root) for arg in s["args"]), sep="\n")' ) plugin_timeout="$( python -c 'import json; print(json.load(open("plugins/hypermnesia-mcp-codex/.mcp.json"))["mcpServers"]["cortex"]["startup_timeout_sec"])' @@ -351,13 +353,17 @@ jobs: python -c 'import json; print(json.load(open("plugins/hypermnesia-mcp-codex/.mcp.json"))["mcpServers"]["cortex"]["env"]["CORTEX_RUNTIME"])' )" candidate_wheel="$(find "$RUNNER_TEMP/cortex-codex-wheel" -name '*.whl' -print -quit)" - # Install verifier dependencies outside the cold cache used by the - # manifest command; full-profile bounds come from this exact tree. + # source: docs/verification/codex-hooks-20261002.md + # Prepare the candidate explicitly; event startup never installs it. + export UV_FIND_LINKS="$RUNNER_TEMP/cortex-codex-wheel" + export UV_CACHE_DIR="$RUNNER_TEMP/cortex-codex-cold-uv-cache" + export UV_TOOL_DIR="$RUNNER_TEMP/cortex-codex-cold-uv-tools" + uv tool install --python "$(command -v python3)" --no-build \ + "hypermnesia-mcp[postgresql,sqlite] @ file://${candidate_wheel}" + # The verifier and manifest runtime inherit the same prepared paths. uv run --no-project --with "$candidate_wheel" -- env \ CORTEX_RUNTIME="$plugin_runtime" \ UV_FIND_LINKS="$RUNNER_TEMP/cortex-codex-wheel" \ - UV_CACHE_DIR="$RUNNER_TEMP/cortex-codex-cold-uv-cache" \ - UV_TOOL_DIR="$RUNNER_TEMP/cortex-codex-cold-uv-tools" \ PYTHONPATH="$GITHUB_WORKSPACE" \ python scripts/verify_mcp_hosts.py \ --timeout "$plugin_timeout" --clients codex-cli --profiles full \ diff --git a/docs/codex-plugin.md b/docs/codex-plugin.md index 48dd9cbe..e2484ff6 100644 --- a/docs/codex-plugin.md +++ b/docs/codex-plugin.md @@ -23,34 +23,21 @@ MCP-only, `lean`-profile package. ## How the hooks run under Codex -A Codex plugin ships only its own directory, never this repository, and never -`scripts/launcher.py`, which is Claude-only. Runtime hooks invoke the -console script the wheel declares (`hypermnesia-mcp-hook`, `pyproject.toml`, -added in #605): +The bundled `scripts/runtime.py` checks the installed uv tool's wheel version +and executes its isolated interpreter (`-I`). The hook command is: -```bash -uvx --from "hypermnesia-mcp[postgresql,sqlite]==4.23.5" hypermnesia-mcp-hook +```sh +python3 "${PLUGIN_ROOT}/scripts/runtime.py" ``` -`mcp_server/hooks/entry.py` validates `` against `HOOK_MODULES`, wires -the composition root (issue #560), reads the one stdin event, normalizes it -(`mcp_server/hooks/host_event.py`, #608) and dispatches to the hook module -unchanged. Codex's `apply_patch` calls are expanded into one Edit/Write event -per file operation, `exec_command`/`shell_command` become a `Bash`-shaped -event, and `SubagentStart`'s `agent_type` is mapped to `agent_name`; a -Claude-shaped event passes through untouched. - -Runtime commands check that `uvx` is present and report a named diagnostic if -it is missing. Session-end intake and startup recovery use the bundled -`${PLUGIN_ROOT}/scripts/session_queue.py` through Python 3. They do not import -the runtime before persisting or scheduling work. +No event resolves dependencies, downloads packages or compiles native extensions. +Setup prepares the environment separately; absent or stale installations fail +with a named setup diagnostic. The wheel's `mcp_server/hooks/entry.py` validates +the hook module and wires the configured backend. SessionEnd first persists +its event using the bundled standard-library queue, then invokes this same +runtime in a replayable worker. No repository module can shadow the wheel. -The MCP server and runtime hooks pin the wheel to the plugin version. This -prevents a cached older wheel from silently handling newer event contracts. -CI builds that candidate wheel and supplies it through `UV_FIND_LINKS` before -the version is published; deployment uses the same requirement from PyPI. - -### Event names and matchers +## Event names and matchers Event names are Codex's own, verified against [learn.chatgpt.com/docs/hooks](https://learn.chatgpt.com/docs/hooks) (read @@ -125,20 +112,18 @@ The call continues through the normal permission flow, so don't count on a stalled hook to act as a gate." A timeout on a gate therefore fails **open**, so a tight one would trade a rare long wait for silently ungated edits. Warm, these cost 0.16s to 0.26s (measured 2026-09-22, same conditions as -above); the long wait is only the first cold `uvx` resolve, which the prewarm -removes. Note that this exposure is identical on Claude Code today, so it is -a property of both manifests rather than something Codex introduces. +above). The current Codex dispatcher requires prepared dependencies; +no package resolution occurs during an event. Leaving the rest unset would not have been the parity case: on -`UserPromptSubmit`, a stalled `uvx` resolve or a blocked database would hold +`UserPromptSubmit`, a blocked database would hold up every prompt for ten minutes where Claude Code caps the same hook at five seconds. For those, failing open is the right trade, because what a cancelled -run costs is one skipped enrichment. A cold `uv` cache will exceed those -budgets; prewarming (below) removes the window. +run costs is one skipped enrichment. An absent runtime is reported immediately with the setup instruction. ### Cost per edit -Every runtime hook is its own `uvx` process, so one `apply_patch`, `Edit` or `Write` +Every runtime hook is its own Python process, so one `apply_patch`, `Edit` or `Write` fires up to five of them: `decision_gate` and `no_deps_gate` before the call, then `post_tool_capture`, `preemptive_context` and `pipeline_impact_bump` after it. A patch touching several files still costs five processes, not five @@ -149,8 +134,8 @@ Measured on 2026-09-22 (macOS 26.6.2 arm64, uv 0.11.3, warm `uv` cache, published 4.23.1 wheel), one such process takes 0.18s to 0.21s in steady state, with the first invocation of a given module slower (1.3s to 5.1s observed) while its caches fill. The two gates are the ones in the blocking -path, at roughly 0.4s of that total. On a cold cache the first hook pays the -full resolve instead, which is what the prewarm below is for. +path, at roughly 0.4s of that total. These historical measurements used the former uvx dispatcher. +Current dispatcher measurements are in `verification/codex-hooks-20261002.md`. Matchers are widened to carry Codex's native tool names alongside Claude's. The Codex docs state that for `apply_patch` "hook input still reports @@ -189,7 +174,7 @@ codex plugin add hypermnesia-mcp-codex@cortex-codex-plugins ``` Restart the ChatGPT desktop app and start a new task so Codex loads the new -plugin components. The plugin uses `uvx`, so `uv` must be available on `PATH`. +plugin components. The dispatcher uses `uv tool dir`, so `uv` must be available on `PATH`. The first launch installs both storage drivers. Direct MCP startup reads the same `~/.claude/methodology/backend.json` selection as the Claude launcher before loading memory settings. `CORTEX_CLAUDE_DIR` relocates that shared @@ -207,34 +192,20 @@ configured but unreachable database URL remains an error rather than silently redirecting writes. Both hosts must use the same configuration root and storage settings to share memories; this does not merge previously separate stores. -A prewarm downloads the package before restarting Codex: +Prepare the matching wheel with the native Python before restarting Codex: -```bash -uv tool install "hypermnesia-mcp[postgresql,sqlite]==4.23.5" +```sh +python3 "/scripts/runtime.py" setup ``` -For the MCP server this is only a startup optimization, `startup_timeout_sec` -already covers a cold resolve. For the lifecycle hooks it matters more: every -hook is its own `uvx` invocation, so a cold cache makes the first one pay the -full package resolve. Prewarming removes that window. Session-end intake runs before package resolution; a cold worker keeps its event -queued until recording completes. - -The bundled server declares `startup_timeout_sec: 180`. This is a bounded -startup ceiling, not a delay. Re-measured for the full profile on 2026-09-22 -with `scripts/verify_mcp_hosts.py`, the same script and flags CI runs, the -exact two-driver command below completed `initialize`, `tools/list`, and a real -`memory_stats` call over **59 tools in 120.17 seconds** from clean -`UV_CACHE_DIR` and `UV_TOOL_DIR` directories on macOS 26.6.2 arm64 with uv -0.11.3. The next run from that cache completed the same contract in 4.24 -seconds. CI reads the command, runtime policy, and timeout from the manifest -itself and repeats the clean-cache contract against the `full` profile. - +This explicit setup is required for both MCP and lifecycle hooks. It installs +binary wheels into the uv tool environment. SessionEnd preserves failures in +its queue for later recovery. The MCP server retains its 180-second startup +ceiling; this includes server initialization, not dependency preparation. The bundled MCP command is equivalent to: -```bash -env CORTEX_RUNTIME=cowork \ - uvx --from "hypermnesia-mcp[postgresql,sqlite]==4.23.5" \ - hypermnesia-mcp +```sh +env CORTEX_RUNTIME=cowork python3 "${PLUGIN_ROOT}/scripts/runtime.py" server ``` `CORTEX_RUNTIME=cowork` selects Cortex's existing DB-optional local-runtime @@ -265,3 +236,27 @@ this local package. See [shared memory and decisions](shared-host-memory.md) for the common storage and ADR-root contract, opt-in authoring, and the limits of the handoff tests. + +## Codex runtime setup and diagnosis (2 October 2026) + +The bundled `scripts/runtime.py` dispatches hooks through the installed +`hypermnesia-mcp` uv tool environment and verifies its version against the plugin +manifest. An absent or mismatched runtime fails with an explicit setup message. +Hooks and SessionEnd replay do not resolve, download or compile dependencies. + +Before trusting the hooks, install the matching wheel using the native Python: + +```sh +python3 "/scripts/runtime.py" setup +``` + +Setup uses `uv tool install --python --no-build`; use a +native interpreter on Apple Silicon. Source changes cannot repair an already +published wheel: the published Intel cryptography bound needs a future release. +After a plugin update, review changed definitions in the native `/hooks` browser. +Do not write trust hashes or bypass review. A prepared runtime or direct-hook +test proves neither native event delivery nor successful memory persistence. + +The 2 October failure occurred before hook code loaded: unqualified uvx selected +Intel CPython on an ARM host and attempted cryptography compilation, then exceeded +5/10-second hook deadlines. See `docs/verification/codex-hooks-20261002.md`. diff --git a/docs/verification/codex-hooks-20261002.md b/docs/verification/codex-hooks-20261002.md new file mode 100644 index 00000000..150bba14 --- /dev/null +++ b/docs/verification/codex-hooks-20261002.md @@ -0,0 +1,67 @@ +# Codex hooks repair — 2 October 2026 + +Source baseline: c32a6a025319407630cab4733a4e0b17ae2d9588, local edits only. +Host: macOS ARM, Codex CLI 0.160.0; desktop binary 0.159.0. + +## Confirmed failure + +All 28 original hooks were enabled and trusted according to native `hooks/list`. +The screenshot supplied by the owner shows repeated deadlines of 5/10 seconds +and exit code 1. Running the exact Cortex uvx command reproduced compilation of +cryptography50.0.2 for x86_64 on an aarch64 host. The compile failed because the +Intel Rust target and cross-compilation OpenSSL configuration were absent. +Installing the ARM uv tool alone did not change unqualified uvx selection. + +## Local changes + +The plugin dispatcher now validates the installed wheel version and launches its +isolated Python. Hooks, SessionEnd replay and MCP startup do not resolve packages. +Setup explicitly installs binary wheels with its native Python. The standalone +MCP configuration uses the same prepared Python; its previous pin was4.23.4 +while installed hooks used4.23.5. Backend environment remains PostgreSQL. +Published runtime metadata now contains the Intel cryptography<49 bound already +documented by ADR-1092; no package, version or source changed in uv.lock. + +## Verification + +136 targeted tests pass (130 lifecycle/runtime tests, three documentation +contracts, two CI contracts and one telemetry regression): manifest contracts, runtime version checks, isolated +server/hook arguments, interruption recovery and concurrent queue deduplication, +plus published platform bounds. Ruff, craftsmanship and git diff --check pass. +Direct event probes return0: post_tool_capture1.148s, preemptive_context0.628s, +post_commit_reindex0.424s. Capture reports persistence pending; these exit codes +do not prove memory was committed. MCP initialization3.073s, tools/list59 tools; +query_methodology returns successfully through the restored local MCP server. +Recall exceeded both the initial 30-second diagnostic budget and a subsequent +20-second official-client budget while loading the embedding model; tool latency +remains unverified. These probes do not establish a recall regression. Owned +diagnostic servers were stopped. + +Full installed SessionStart now returns0 in two consecutive probes:7.302s +and1.057s, emitting3128/3131bytes without printing memory content. Its connection +disables JIT locally, the grooming query uses the existing tags index, and the +banner checks distribution metadata without importing Torch/SciPy. See +[captured query evidence](codex-session-start-query-20261002.md). These are direct +manual probes, not native lifecycle delivery evidence. Cache/load conditions +differ; the measurements do not establish a guaranteed latency. + +Native hooks/list after explicit owner approval:28 definitions, all28 trusted, +no parsing errors in Transartica, Cortex, Session Optimizer and Zetetic. +Native app-server notifications from two fresh threads confirm Cortex +SessionStart1.467/1.709s, UserPromptSubmit0.322/0.333s, three matching +PostToolUse handlers0.183–0.334s and SessionEnd0.102/0.107s all completed. +The command probe was a real model-issued printf, followed by thread/archive. +The two captures also found invalid SessionStart JSON from disk-hygiene and +statusline; those are separate plugin repairs and prevent claiming the whole +installation has zero hook errors. PreCompact, edit gates and subagent events +were not triggered in these cycles and remain unverified natively. + +The first native trust-all attempt was rejected by automatic approval review. +The owner subsequently approved the exact11Hypermnesia hooks; approval was +applied through Codex /hooks, then verified across the four repositories. +No trust hashes were rewritten outside the native interface. + +This report precedes PR publication. No release, database migration or deletion +of shared caches was performed. +Concurrent untracked work remains untouched. Old installed definitions and +config are preserved in ~/.codex/backups for review/recovery. diff --git a/docs/verification/codex-session-start-query-20261002.md b/docs/verification/codex-session-start-query-20261002.md new file mode 100644 index 00000000..28e1156c --- /dev/null +++ b/docs/verification/codex-session-start-query-20261002.md @@ -0,0 +1,115 @@ +# SessionStart grooming query verification, 2026-10-02 + +The previous query used MAX(created_at) with lesson and prefix filters. +PostgreSQL selected two backward scans of idx_memories_created_at. Neither +prefix had a matching row in the observed corpus, so both scans exhausted +the index. The replacement materializes the lesson subset first, using the +existing idx_memories_tags_gin. Timestamp selection and wiki MAX(tended) +remain identical. No schema, index or stored data was changed. + +Measured from base revision `c32a6a025319407630cab4733a4e0b17ae2d9588` +and the replacement SQL now in the working tree, on the local PostgreSQL +cortex database through the installed 4.23.5 runtime Python and psycopg. The memories heap was 944 MB, total +relation size 3002 MB; statistics estimated 92,862 live rows. Existing +Claude 4.23.4 and Cortex 4.23.5 session_start.py were identical before this +change. This is a query-plan correction, not a demonstrated version regression. + +Both queries ran interleaved in one REPEATABLE READ READ ONLY transaction, +with a LOCAL statement_timeout of 60 seconds. This is an observation limit, +not a new hook timeout or algorithm constant. The database was live, with +concurrent activity and warmed pages from earlier probes; the result is not +a clean-cache guarantee or a benchmark of the complete SessionStart hook. + +| Iteration | Previous query, seconds | Replacement, seconds | +| --- | ---: | ---: | +| 1 | 0.619434 | 0.005205 | +| 2 | 0.164163 | 0.012441 | +| 3 | 0.179626 | 0.003813 | + +Every result tuple was identical in the same snapshot. SHA-256 of sorted +JSON timestamp results was +`f30b6917d99fff148374070ce1dc02f09c8c3f5a7389739a616b57ed9d5f3e1e`. + +EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) in the same transaction: + +| Plan | Execution, ms | Planning, ms | Shared hits | Shared reads | +| --- | ---: | ---: | ---: | ---: | +| Previous | 153.232 | 0.502 | 104981 | 10408 | +| Replacement | 5.109 | 0.301 | 870 | 437 | + +The previous plan contained two Index Scan nodes on idx_memories_created_at, +each producing zero matching rows and evaluating the prefix subplan 970 times. +The replacement contained Bitmap Index Scan on idx_memories_tags_gin followed +by Bitmap Heap Scan of 970 lesson rows. Both prefix aggregates scanned that +materialized subset. Both plans scanned the same 3023 wiki pages. JIT was +absent from these two grooming plans. + +Reproduce by extracting the SQL passed to conn.execute in +_fetch_grooming_staleness from HEAD and the working tree, running each against +the same read-only repeatable-read snapshot, asserting result equality, +and collecting the EXPLAIN JSON. The regression file +`tests_py/hooks/test_session_start_grooming_plan.py` executes the actual query +against synthetic VALUES rows through an explicit CORTEX_TEST_DATABASE_URL. +It verifies empty input, nullable timestamps, lesson exclusion, both prefixes +and their timestamp maxima without writing to the database. + +The pending-curations query and team-decisions query also scan the memories +heap. Their remaining cost must be measured in the full hook before claiming +that SessionStart satisfies Codex's 30-second deadline. + +SessionStart connection JIT policy + +The root agent measured the installed full SessionStart hook failing to finish +within 30 or 35 seconds in three baseline probes. The same installed hook +with process-only PGOPTIONS='-c jit=off' completed in 15.147 seconds, returned +zero and emitted 3058 bytes. This was a manual full-hook probe, not native +Codex delivery evidence. The source now requests options='-c jit=off' only +on SessionStart's psycopg connection. It does not set PGOPTIONS or change +server, background-worker or persistent database configuration. + +PostgreSQL reported jit=on and jit_above_cost=100000. The pending-curations +plan cost was 124074.8, above that threshold. In a separate read-only probe, +that query exceeded a six-second statement limit with the default JIT policy; +with SET LOCAL jit=off it executed in 1456.186 ms, plus 1407.691 ms planning. +These probes had concurrent load and changing cache state, so their individual +query timings alone do not isolate JIT causally. The root full-hook probe +supplies the direct process-level comparison motivating the scoped policy. + +The regression verifies the connection requests jit=off while preserving +the process environment. A subsequent installed-wheel full-hook probe is +required to confirm the combined source corrections within the 30-second +Codex budget. + +Focused verification completed: five tests passed in 0.17 seconds with +`PYTHONDONTWRITEBYTECODE=1 .venv/bin/python -m pytest --noconftest -p no:cacheprovider -o addopts='' tests_py/hooks/test_session_start_grooming_plan.py -q`. +An explicit CORTEX_TEST_DATABASE_URL selected the read-only connection; +the SQL fixtures never accessed or modified stored memories. Ruff check, +Ruff format check, craftsmanship and git diff --check passed for the owned +Python files. + +Banner dependency presence check + +After installing the SQL and connection fixes, a direct installed +SessionStart entry trace returned zero in 12.693 seconds and emitted 3163 +bytes. The ten-second faulthandler snapshot located execution in +_build_context -> _has_sentence_transformers -> sentence_transformers.base.model +-> torch.distributed.tensor imports. A separate availability-only process +spent 28.249 seconds in the same helper; its ten-second snapshot traversed +sentence_transformers, sklearn and scipy compiled-extension imports. +The processes used the installed Python with -I -B, and captured context +was not printed or stored in this report. These timings have different +cache states and concurrent machine activity; they are not a paired speedup. + +The banner now reads the sentence-transformers distribution metadata instead +of importing the ML stack. This checks installation presence only. It does +not establish that transitive imports, embeddings or semantic search work. +The missing-package message reports absence, without claiming a background +installation or promising that the next session will repair it. Regression +tests reject sentence_transformers, torch, scipy and sklearn imports while +building the banner for both present and missing distribution metadata. + +The replacement presence helper, evaluated in the same installed runtime +without invoking the hook, returned true in 0.056733 seconds. Both banner +regressions passed in 0.15 seconds. Ruff check, format check, craftsmanship +and git diff --check passed after this change. The full installed hook must +be verified again after the wheel includes this final source correction. diff --git a/mcp_server/hooks/session_start.py b/mcp_server/hooks/session_start.py index f46bf2dc..bc49f6e4 100644 --- a/mcp_server/hooks/session_start.py +++ b/mcp_server/hooks/session_start.py @@ -71,13 +71,17 @@ def _read_event() -> dict: return {} -def _has_sentence_transformers() -> bool: - """Check if sentence-transformers is importable.""" - try: - import sentence_transformers # noqa: PLC0415, F401 — optional-feature probe: ImportError here is a handled degraded mode +def _sentence_transformers_installed() -> bool: + """Check distribution presence; this does not validate semantic readiness. + + source: docs/verification/codex-session-start-query-20261002.md + """ + from importlib.metadata import PackageNotFoundError, version # noqa: PLC0415 — banner needs package metadata without importing its ML dependencies + try: + version("sentence-transformers") return True - except ImportError: + except PackageNotFoundError: return False @@ -136,8 +140,13 @@ def _connect_pg(): import psycopg # noqa: PLC0415 — optional dependency ([postgresql] extra); imported where used so environments without it keep working from psycopg.rows import DictRow, dict_row # noqa: PLC0415 — optional dependency ([postgresql] extra); imported where used so environments without it keep working + # source: docs/verification/codex-session-start-query-20261002.md + # The short-lived hook cannot amortize JIT compilation for banner SQL. return psycopg.Connection[DictRow].connect( - _DATABASE_URL, row_factory=dict_row, autocommit=True + _DATABASE_URL, + row_factory=dict_row, + autocommit=True, + options="-c jit=off", ) except Exception as exc: # noqa: BLE001 — hook boundary — failure is logged to the hook log; the hook stays non-fatal _log(f"PostgreSQL connect failed: {exc}") @@ -402,16 +411,20 @@ def _fetch_grooming_staleness(conn) -> list[str]: from mcp_server.core.grooming_health import is_stale # noqa: PLC0415 — hook latency boundary: the per-event hook process defers the handler/store stack (hook boot ~0.05 s vs ~0.6 s registry import, measured 2026-07-28) row = conn.execute( + # source: docs/verification/codex-session-start-query-20261002.md + # Materialize the indexed lesson subset before MAX: otherwise the + # planner scans the created_at index backwards for absent prefixes. + "WITH lessons AS MATERIALIZED (" + " SELECT created_at, tags FROM memories " + " WHERE tags @> '[\"lesson\"]'::jsonb) " "SELECT " " (SELECT MAX(tended) FROM wiki.pages) AS wiki_last, " - " (SELECT MAX(created_at) FROM memories m " - " WHERE m.tags @> '[\"lesson\"]'::jsonb " - " AND EXISTS (SELECT 1 FROM jsonb_array_elements_text(m.tags) tg " - " WHERE tg LIKE 'distill-of:%')) AS distill_last, " - " (SELECT MAX(created_at) FROM memories m " - " WHERE m.tags @> '[\"lesson\"]'::jsonb " - " AND EXISTS (SELECT 1 FROM jsonb_array_elements_text(m.tags) tg " - " WHERE tg LIKE 'promoted:%')) AS promo_last" + " (SELECT MAX(created_at) FROM lessons m " + " WHERE EXISTS (SELECT 1 FROM jsonb_array_elements_text(m.tags) tg " + " WHERE tg LIKE 'distill-of:%')) AS distill_last, " + " (SELECT MAX(created_at) FROM lessons m " + " WHERE EXISTS (SELECT 1 FROM jsonb_array_elements_text(m.tags) tg " + " WHERE tg LIKE 'promoted:%')) AS promo_last" ).fetchone() if not row: return [] @@ -718,13 +731,12 @@ def _build_context( "read the full memory with `recall(memory_id=id)`.*" ) - # Warn if semantic search is degraded - if not _has_sentence_transformers(): + # Report missing installation without importing the semantic stack. + if not _sentence_transformers_installed(): lines.append("") lines.append( - "*Note: sentence-transformers is installing in the background. " - "Semantic search will improve next session. " - "Run `pip install sentence-transformers` to install immediately.*" + "*sentence-transformers is not installed in this runtime. " + "Semantic search requires that package.*" ) return "\n".join(lines) diff --git a/plugins/hypermnesia-mcp-codex/.mcp.json b/plugins/hypermnesia-mcp-codex/.mcp.json index 6a222a3f..d7962739 100644 --- a/plugins/hypermnesia-mcp-codex/.mcp.json +++ b/plugins/hypermnesia-mcp-codex/.mcp.json @@ -1,11 +1,10 @@ { "mcpServers": { "cortex": { - "command": "uvx", + "command": "python3", "args": [ - "--from", - "hypermnesia-mcp[postgresql,sqlite]==4.23.5", - "hypermnesia-mcp" + "${PLUGIN_ROOT}/scripts/runtime.py", + "server" ], "env": { "CORTEX_RUNTIME": "cowork" diff --git a/plugins/hypermnesia-mcp-codex/README.md b/plugins/hypermnesia-mcp-codex/README.md index 97790ab8..cb9a7bc3 100644 --- a/plugins/hypermnesia-mcp-codex/README.md +++ b/plugins/hypermnesia-mcp-codex/README.md @@ -16,16 +16,16 @@ codex plugin add hypermnesia-mcp-codex@cortex-codex-plugins ``` Restart the ChatGPT desktop app and start a new task. The plugin launches the -server and runtime hooks with `uvx`, so `uv` must be on `PATH`. Python 3 -must also be on `PATH` for durable session-end intake. The first launch -resolves the `hypermnesia-mcp[postgresql,sqlite]` release from PyPI; later -launches run from the cache. Prewarming that cache is worth it, see -[docs/codex-plugin.md](https://github.com/cdeust/Cortex/blob/main/docs/codex-plugin.md): +server and hooks through an explicitly prepared wheel environment. Install +`uv`, then prepare that runtime using the native Python: -```bash -uv tool install "hypermnesia-mcp[postgresql,sqlite]==4.23.5" +```sh +python3 "/scripts/runtime.py" setup ``` +The dispatcher checks the wheel version and isolates Python imports. Hooks +never resolve dependencies or compile packages. + ## What it exposes `.mcp.json` starts `hypermnesia-mcp` over stdio with no `--profile` flag, so @@ -33,7 +33,7 @@ Codex gets the default `full` tool profile, the same surface the Claude Code plugin serves. `hooks/hooks.json` wires the 11 lifecycle hooks, each as -`uvx --from "hypermnesia-mcp[postgresql,sqlite]==4.23.5" hypermnesia-mcp-hook ` +`python3 "${PLUGIN_ROOT}/scripts/runtime.py" ` (or the bundled durable intake for session end): session-start context injection, per-prompt auto-recall, auto-capture of significant tool output, preemptive context, pipeline heat bumps, post-commit @@ -62,3 +62,27 @@ PostgreSQL target was supplied. An explicitly configured but unreachable ## License MIT, see [LICENSE](./LICENSE). + +## Codex runtime setup and diagnosis (2 October 2026) + +The bundled `scripts/runtime.py` dispatches hooks through the installed +`hypermnesia-mcp` uv tool environment and verifies its version against the plugin +manifest. An absent or mismatched runtime fails with an explicit setup message. +Hooks and SessionEnd replay do not resolve, download or compile dependencies. + +Before trusting the hooks, install the matching wheel using the native Python: + +```sh +python3 "/scripts/runtime.py" setup +``` + +Setup uses `uv tool install --python --no-build`; use a +native interpreter on Apple Silicon. Source changes cannot repair an already +published wheel: the published Intel cryptography bound needs a future release. +After a plugin update, review changed definitions in the native `/hooks` browser. +Do not write trust hashes or bypass review. A prepared runtime or direct-hook +test proves neither native event delivery nor successful memory persistence. + +The 2 October failure occurred before hook code loaded: unqualified uvx selected +Intel CPython on an ARM host and attempted cryptography compilation, then exceeded +5/10-second hook deadlines. See `docs/verification/codex-hooks-20261002.md`. diff --git a/plugins/hypermnesia-mcp-codex/SECURITY.md b/plugins/hypermnesia-mcp-codex/SECURITY.md index 02337ad6..c6fda3de 100644 --- a/plugins/hypermnesia-mcp-codex/SECURITY.md +++ b/plugins/hypermnesia-mcp-codex/SECURITY.md @@ -72,9 +72,9 @@ disable the plugin's hooks in Codex, to run the MCP server alone. (see [PRIVACY.md](https://github.com/cdeust/Cortex/blob/main/PRIVACY.md)). - Files referenced by the events the hooks receive, read-only, as described above. No hook writes to your repository. -- The `uvx` cache, used for server and runtime-hook startup. The package - requirement is pinned to the installed plugin version. Intake does not wait - for package startup before persisting the session-end event. +- The installed uv tool environment, prepared separately with binary wheels. + Runtime version validation matches the plugin; isolated Python imports prevent + project modules from shadowing it. Intake persists before starting the worker. Nothing leaves the machine except the one-time model download described in PRIVACY.md. diff --git a/plugins/hypermnesia-mcp-codex/hooks/hooks.json b/plugins/hypermnesia-mcp-codex/hooks/hooks.json index aa81c8e9..d39567cf 100644 --- a/plugins/hypermnesia-mcp-codex/hooks/hooks.json +++ b/plugins/hypermnesia-mcp-codex/hooks/hooks.json @@ -6,11 +6,11 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook decision_gate'" + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" decision_gate" }, { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook no_deps_gate'" + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" no_deps_gate" } ] }, @@ -19,7 +19,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook agent_briefing'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" agent_briefing", "timeout": 5 } ] @@ -30,7 +30,7 @@ "hooks": [ { "type": "command", - "command": "python3 \"${PLUGIN_ROOT}/scripts/session_queue.py\" recover; bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook session_start'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/session_queue.py\" recover; python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" session_start", "timeout": 30 } ] @@ -41,7 +41,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook auto_recall'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" auto_recall", "timeout": 5 } ] @@ -53,7 +53,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook post_tool_capture'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" post_tool_capture", "timeout": 10 } ] @@ -63,7 +63,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook preemptive_context'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" preemptive_context", "timeout": 5 } ] @@ -73,7 +73,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook pipeline_impact_bump'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" pipeline_impact_bump", "timeout": 5 } ] @@ -83,7 +83,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook post_commit_reindex'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" post_commit_reindex", "timeout": 10 } ] @@ -105,7 +105,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook compaction_checkpoint'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" compaction_checkpoint", "timeout": 10 } ] @@ -116,7 +116,7 @@ "hooks": [ { "type": "command", - "command": "bash -c 'command -v uvx >/dev/null 2>&1 || { echo \"cortex hook: uvx is not on PATH; install uv so Codex can run Cortex lifecycle hooks\" >&2; exit 1; }; exec uvx --from \"hypermnesia-mcp[postgresql,sqlite]==4.23.5\" hypermnesia-mcp-hook agent_briefing'", + "command": "python3 \"${PLUGIN_ROOT}/scripts/runtime.py\" agent_briefing", "timeout": 5 } ] diff --git a/plugins/hypermnesia-mcp-codex/scripts/runtime.py b/plugins/hypermnesia-mcp-codex/scripts/runtime.py new file mode 100644 index 00000000..0b24a0d8 --- /dev/null +++ b/plugins/hypermnesia-mcp-codex/scripts/runtime.py @@ -0,0 +1,81 @@ +"""Run only the explicitly installed Cortex wheel; never resolve in a hook. + +Source: native Codex failure, 2026-10-02: uvx picked Intel CPython on an ARM +host and rebuilt cryptography until the event deadline. Setup is a separate +command; version validation prevents silent use of an older installed tool. +""" + +from __future__ import annotations + +import email.parser +import json +import os +from pathlib import Path +import subprocess +import sys + + +def requirement() -> tuple[str, str]: + manifest = Path(__file__).resolve().parents[1] / ".codex-plugin/plugin.json" + version = json.loads(manifest.read_text())["version"] + return version, f"hypermnesia-mcp[postgresql,sqlite]=={version}" + + +def installed_python(version: str) -> Path: + directory = subprocess.check_output(["uv", "tool", "dir"], text=True).strip() + runtime = Path(directory) / "hypermnesia-mcp" + metadata = list( + runtime.glob("lib/python*/site-packages/hypermnesia_mcp-*.dist-info/METADATA") + ) + metadata += list( + runtime.glob("Lib/site-packages/hypermnesia_mcp-*.dist-info/METADATA") + ) + if len(metadata) != 1: + raise RuntimeError("Cortex runtime absent; run runtime.py setup first") + installed = email.parser.Parser().parsestr(metadata[0].read_text())["Version"] + if installed != version: + raise RuntimeError( + f"Cortex runtime {installed} differs from plugin {version}; " + "run runtime.py setup" + ) + python = runtime / ("Scripts/python.exe" if os.name == "nt" else "bin/python") + if not python.is_file(): + raise RuntimeError(f"Cortex runtime interpreter absent: {python}") + return python + + +def main() -> None: + version, package = requirement() + arguments = sys.argv[1:] + if not arguments or (len(arguments) != 1 and arguments[0] != "server"): + raise RuntimeError("usage: runtime.py setup|server [args...]|") + module = sys.argv[1] + if module == "setup": + subprocess.run( + [ + "uv", + "tool", + "install", + "--python", + sys.executable, + "--no-build", + package, + ], + check=True, + ) + installed_python(version) + return + python = installed_python(version) + if module == "server": + os.execv(str(python), [str(python), "-I", "-m", "mcp_server", *arguments[1:]]) + return + command = "from mcp_server.hooks.entry import main; main()" + os.execv(str(python), [str(python), "-I", "-c", command, module]) + + +if __name__ == "__main__": + try: + main() + except (OSError, RuntimeError, subprocess.SubprocessError) as exc: + print(f"[cortex runtime] {exc}", file=sys.stderr) + raise SystemExit(1) from exc diff --git a/plugins/hypermnesia-mcp-codex/scripts/session_queue.py b/plugins/hypermnesia-mcp-codex/scripts/session_queue.py index 37333b9d..7a547187 100644 --- a/plugins/hypermnesia-mcp-codex/scripts/session_queue.py +++ b/plugins/hypermnesia-mcp-codex/scripts/session_queue.py @@ -149,12 +149,6 @@ def job_lock(path): os.close(fd) -def package_requirement(): - manifest = Path(__file__).resolve().parents[1] / ".codex-plugin/plugin.json" - version = json.loads(manifest.read_text())["version"] - return f"hypermnesia-mcp[postgresql,sqlite]=={version}" - - def run_job(path): if receipt(path).exists(): path.unlink() @@ -169,10 +163,8 @@ def run_job(path): env.update(job["environment"]) result = subprocess.run( [ - "uvx", - "--from", - package_requirement(), - "hypermnesia-mcp-hook", + sys.executable, + str(Path(__file__).with_name("runtime.py")), "session_lifecycle", ], input=json.dumps(job["event"]), diff --git a/pyproject.toml b/pyproject.toml index a71de524..92aaeaec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,10 @@ classifiers = [ "Topic :: Software Development :: Libraries", ] dependencies = [ + # source: ADR-1092 + # macOS Intel wheels stop at cryptography 48. + # uvx resolves published metadata without the lock-shaping platform group. + "cryptography<49 ; sys_platform == 'darwin' and platform_machine == 'x86_64'", # source: ADR-0874 # # diff --git a/tests_py/hooks/test_hook_telemetry.py b/tests_py/hooks/test_hook_telemetry.py index 6ea287c1..2b4d74d1 100644 --- a/tests_py/hooks/test_hook_telemetry.py +++ b/tests_py/hooks/test_hook_telemetry.py @@ -193,7 +193,7 @@ def _patch_session_main(monkeypatch): "_count_pending_curations": 0, "_fetch_grooming_staleness": [], "_emit_banner_receipt": 7, - "_has_sentence_transformers": True, + "_sentence_transformers_installed": True, "_detect_external_sources": [], } for name, value in values.items(): diff --git a/tests_py/hooks/test_session_queue.py b/tests_py/hooks/test_session_queue.py index 6f4b56e2..78fb25e8 100644 --- a/tests_py/hooks/test_session_queue.py +++ b/tests_py/hooks/test_session_queue.py @@ -93,16 +93,18 @@ def test_interrupted_worker_leaves_event_for_next_drain(queue, tmp_path, monkeyp key = queue.enqueue(root, {"session_id": "interrupted"}) fifo = tmp_path / "ready" os.mkfifo(fifo) - uvx = tmp_path / "uvx" - uvx.write_text( + sandbox_script = tmp_path / "session_queue.py" + sandbox_script.write_text(SCRIPT.read_text()) + runtime_script = tmp_path / "runtime.py" + runtime_script.write_text( f"#!{sys.executable}\nimport os, signal\n" f"f=os.open({str(fifo)!r}, os.O_WRONLY)\n" "os.write(f,b'R')\nsignal.pause()\n" ) - uvx.chmod(0o700) + runtime_script.chmod(0o700) monkeypatch.setenv("PATH", str(tmp_path) + os.pathsep + os.environ["PATH"]) worker = subprocess.Popen( - [sys.executable, "-S", str(SCRIPT), "drain"], start_new_session=True + [sys.executable, "-S", str(sandbox_script), "drain"], start_new_session=True ) try: with fifo.open("rb", buffering=0) as ready: @@ -111,8 +113,8 @@ def test_interrupted_worker_leaves_event_for_next_drain(queue, tmp_path, monkeyp finally: os.killpg(worker.pid, signal.SIGKILL) worker.wait() - uvx.write_text(f"#!{sys.executable}\n") - subprocess.run([sys.executable, "-S", str(SCRIPT), "drain"], check=True) + runtime_script.write_text(f"#!{sys.executable}\n") + subprocess.run([sys.executable, "-S", str(sandbox_script), "drain"], check=True) assert queue.receipt(root / f"{key}.json").exists() @@ -120,16 +122,19 @@ def test_concurrent_drains_process_event_once(queue, tmp_path, monkeypatch): root = queue.queue_root() queue.enqueue(root, {"session_id": "concurrent"}) count = tmp_path / "calls" - uvx = tmp_path / "uvx" - uvx.write_text( + sandbox_script = tmp_path / "session_queue.py" + sandbox_script.write_text(SCRIPT.read_text()) + runtime_script = tmp_path / "runtime.py" + runtime_script.write_text( f"#!{sys.executable}\nfrom pathlib import Path\n" f"p=Path({str(count)!r})\n" "with p.open('a') as f: f.write('called\\n')\n" ) - uvx.chmod(0o700) + runtime_script.chmod(0o700) monkeypatch.setenv("PATH", str(tmp_path) + os.pathsep + os.environ["PATH"]) workers = [ - subprocess.Popen([sys.executable, "-S", str(SCRIPT), "drain"]) for _ in range(2) + subprocess.Popen([sys.executable, "-S", str(sandbox_script), "drain"]) + for _ in range(2) ] assert [worker.wait() for worker in workers] == [0, 0] assert count.read_text().splitlines() == ["called"] @@ -146,11 +151,17 @@ def test_nonzero_worker_keeps_event_unacknowledged(queue): assert "exited 1" in (root / f"{key}.error").read_text() -def test_worker_requires_matching_plugin_version(queue): - manifest = json.loads((SCRIPT.parents[1] / ".codex-plugin/plugin.json").read_text()) - assert queue.package_requirement() == ( - "hypermnesia-mcp[postgresql,sqlite]==" + manifest["version"] - ) +def test_replay_uses_prepared_runtime_without_uvx(queue): + root = queue.queue_root() + queue.enqueue(root, {"session_id": "runtime-dispatch"}) + with patch.object(queue.subprocess, "run") as run: + run.return_value.returncode = 0 + queue.drain(root) + assert run.call_args.args[0] == [ + sys.executable, + str(SCRIPT.with_name("runtime.py")), + "session_lifecycle", + ] def test_saved_backend_is_frozen_for_replay(queue, monkeypatch): diff --git a/tests_py/hooks/test_session_start_distribution.py b/tests_py/hooks/test_session_start_distribution.py new file mode 100644 index 00000000..373ae1ec --- /dev/null +++ b/tests_py/hooks/test_session_start_distribution.py @@ -0,0 +1,41 @@ +"""Banner installation checks must not import the ML stack. + +source: docs/verification/codex-session-start-query-20261002.md +""" + +from __future__ import annotations + +import builtins +from importlib.metadata import PackageNotFoundError +from unittest.mock import patch + +import pytest + +from mcp_server.hooks import session_start as hook + + +@pytest.mark.parametrize("installed", [True, False]) +def test_banner_checks_distribution_without_loading_ml(installed): + original_import = builtins.__import__ + + def guarded_import(name, *args, **kwargs): + if name.split(".")[0] in {"sentence_transformers", "torch", "scipy", "sklearn"}: + raise AssertionError(f"banner attempted heavy import: {name}") + return original_import(name, *args, **kwargs) + + # Real metadata lookup is isolated from the developer's installed packages. + error = None if installed else PackageNotFoundError("sentence-transformers") + with ( + patch( + "importlib.metadata.version", return_value="installed", side_effect=error + ) as version, + patch.object(builtins, "__import__", side_effect=guarded_import), + ): + context = hook._build_context( + [], [{"id": 1, "content": "fixture", "domain": "", "heat": 0.5}], None + ) + version.assert_called_once_with("sentence-transformers") + assert "## Cortex Memory Context" in context + assert ("not installed in this runtime" in context) is not installed + assert "installing in the background" not in context + assert "improve next session" not in context diff --git a/tests_py/hooks/test_session_start_grooming_plan.py b/tests_py/hooks/test_session_start_grooming_plan.py new file mode 100644 index 00000000..3378047a --- /dev/null +++ b/tests_py/hooks/test_session_start_grooming_plan.py @@ -0,0 +1,138 @@ +"""Read-only PostgreSQL fixtures verify grooming timestamps after prefiltering. + +source: docs/verification/codex-session-start-query-20261002.md +The fixtures use VALUES inside SELECT; no schema or stored rows are changed. +""" + +from __future__ import annotations + +import ast +from datetime import datetime, timezone +import os +from pathlib import Path +import sys +from types import ModuleType +from unittest.mock import Mock, patch + +import pytest + + +def _grooming_sql() -> str: + source = Path(__file__).resolve().parents[2] / "mcp_server/hooks/session_start.py" + tree = ast.parse(source.read_text()) + for function in tree.body: + if ( + isinstance(function, ast.FunctionDef) + and function.name == "_fetch_grooming_staleness" + ): + for call in ast.walk(function): + if ( + isinstance(call, ast.Call) + and isinstance(call.func, ast.Attribute) + and call.func.attr == "execute" + ): + return ast.literal_eval(call.args[0]) + raise AssertionError("grooming query absent") + + +@pytest.mark.skipif( + os.environ.get("CORTEX_MEMORY_STORE_BACKEND", "").strip().lower() == "sqlite", + reason="PostgreSQL SQL fixtures do not apply to the explicit SQLite backend", +) +@pytest.mark.parametrize( + ("rows", "distill_day", "promo_day"), + [ + ([(None, [])], None, None), + ( + [ + ("2026-01-01", ["lesson", "distill-of:a"]), + ("2026-01-02", ["lesson", "promoted:a"]), + ("2026-01-03", ["distill-of:b", "promoted:b"]), + ], + 1, + 2, + ), + ( + [ + ("2026-01-01", ["lesson", "distill-of:a"]), + ("2026-01-02", ["lesson", "distill-of:b", "promoted:b"]), + ("2026-01-03", ["lesson", "x-distill-of:c", "x-promoted:c"]), + ], + 2, + 2, + ), + ([(None, ["lesson", "distill-of:a", "promoted:a"])], None, None), + ], +) +def test_grooming_prefilter_preserves_timestamp_semantics(rows, distill_day, promo_day): + import psycopg + from psycopg.rows import dict_row + from psycopg.types.json import Jsonb + + values = ", ".join("(%s::timestamptz, %s::jsonb)" for _ in rows) + fixtures = ( + f"memory_rows(created_at, tags) AS (VALUES {values}), " + "wiki_rows(tended) AS (VALUES ('2026-01-04T00:00:00+00'::timestamptz)), " + ) + query = ( + _grooming_sql().replace("%", "%%").replace("FROM memories", "FROM memory_rows") + ) + query = query.replace("FROM wiki.pages", "FROM wiki_rows") + query = "WITH " + fixtures + query.removeprefix("WITH ") + parameters = [ + value + for timestamp, tags in rows + for value in ( + f"{timestamp}T00:00:00+00" if timestamp else None, + Jsonb(tags), + ) + ] + # conftest supplies an isolated DATABASE_URL; standalone runs need a DSN. + database_url = ( + os.environ.get("CORTEX_TEST_DATABASE_URL") or os.environ["DATABASE_URL"] + ) + with psycopg.connect(database_url, row_factory=dict_row) as connection: + connection.execute("SET TRANSACTION READ ONLY") + result = connection.execute(query, parameters).fetchone() + + def expected(day): + return datetime(2026, 1, day, tzinfo=timezone.utc) if day else None + + assert result == { + "wiki_last": expected(4), + "distill_last": expected(distill_day), + "promo_last": expected(promo_day), + } + + +def test_session_start_disables_jit_on_its_connection_without_environment_changes(): + source = Path(__file__).resolve().parents[2] / "mcp_server/hooks/session_start.py" + function = next( + node + for node in ast.parse(source.read_text()).body + if isinstance(node, ast.FunctionDef) and node.name == "_connect_pg" + ) + namespace = {"_DATABASE_URL": "postgresql://test.invalid/banner", "_log": print} + exec( + compile(ast.Module(body=[function], type_ignores=[]), str(source), "exec"), + namespace, + ) + environment = dict(os.environ) + connect = Mock() + + class Connection: + @classmethod + def __class_getitem__(cls, row_type): + return cls + + Connection.connect = connect + driver = ModuleType("psycopg") + driver.Connection = Connection + rows = ModuleType("psycopg.rows") + rows.DictRow = dict + rows.dict_row = Mock() + with patch.dict(sys.modules, {"psycopg": driver, "psycopg.rows": rows}): + assert namespace["_connect_pg"]() is connect.return_value + assert connect.call_args.kwargs["options"] == "-c jit=off" + assert connect.call_args.kwargs["autocommit"] is True + assert dict(os.environ) == environment diff --git a/tests_py/scripts/_codex_plugin_support.py b/tests_py/scripts/_codex_plugin_support.py index bd5b4ccd..299a0488 100644 --- a/tests_py/scripts/_codex_plugin_support.py +++ b/tests_py/scripts/_codex_plugin_support.py @@ -30,7 +30,7 @@ # nor scripts/launcher.py. HOOK_CONSOLE_SCRIPT = "hypermnesia-mcp-hook" # How each host's manifest spells the module at the end of a hook command. -CODEX_SUFFIX = HOOK_CONSOLE_SCRIPT + " {module}'" +CODEX_SUFFIX = 'scripts/runtime.py" {module}' CLAUDE_SUFFIX = "mcp_server.hooks.{module}'" diff --git a/tests_py/scripts/test_ci_codex_runtime.py b/tests_py/scripts/test_ci_codex_runtime.py new file mode 100644 index 00000000..3b5c195c --- /dev/null +++ b/tests_py/scripts/test_ci_codex_runtime.py @@ -0,0 +1,57 @@ +"""CI must prepare the wheel before driving the resolved Codex MCP command. + +source: docs/verification/codex-hooks-20261002.md +""" + +from pathlib import Path +import re +import subprocess +import sys + +import yaml + + +REPO = Path(__file__).resolve().parents[2] + + +def _host_step() -> str: + workflow = yaml.safe_load((REPO / ".github/workflows/ci.yml").read_text()) + return next( + step["run"] + for step in workflow["jobs"]["mcp-host-config"]["steps"] + if step.get("name") + == "Validate Claude, Gemini, and Codex configuration parsing" + ) + + +def test_native_host_step_is_valid_shell_and_resolves_plugin_command(): + step = _host_step() + subprocess.run(["bash", "-n"], input=step, text=True, check=True) + expression = next( + code + for code in re.findall(r"python -c '([^']*)'", step) + if "arg.replace" in code + ) + output = subprocess.check_output( + [sys.executable, "-c", expression], cwd=REPO, text=True + ) + command = output.splitlines() + assert command == [ + "python3", + str(REPO / "plugins/hypermnesia-mcp-codex/scripts/runtime.py"), + "server", + ] + assert Path(command[1]).is_file() + assert "${PLUGIN_ROOT}" not in output + + +def test_host_step_prepares_candidate_in_same_environment_as_verifier(): + step = _host_step() + setup = step.index("uv tool install") + verifier = step.index("python scripts/verify_mcp_hosts.py") + assert setup < verifier + for variable in ("UV_CACHE_DIR", "UV_TOOL_DIR", "UV_FIND_LINKS"): + assert step.index(f"export {variable}=") < setup + assert "--no-build" in step[setup:verifier] + assert "hypermnesia-mcp[postgresql,sqlite] @ file://${candidate_wheel}" in step + assert 's["transport"]["command"]=="python3"' in step diff --git a/tests_py/scripts/test_codex_dependency_platform.py b/tests_py/scripts/test_codex_dependency_platform.py new file mode 100644 index 00000000..00b6c951 --- /dev/null +++ b/tests_py/scripts/test_codex_dependency_platform.py @@ -0,0 +1,52 @@ +"""Published dependencies must protect Codex uvx from Intel source builds. + +source: ADR-1092 +cryptography >=49 has no macOS Intel wheel. +source: 2026-10-02 session-end-queue/worker.log:7998-8025, arm64 host +resolving an Intel Python attempted cryptography 50.0.2 and failed. +""" + +from __future__ import annotations + +from pathlib import Path +import sys + +from packaging.requirements import Requirement +import pytest + +# source: tests_py/hooks/test_entry.py, Python >=3.10 compatibility. +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + + +def _published_cryptography_bounds() -> list[Requirement]: + project = Path(__file__).resolve().parents[2] / "pyproject.toml" + metadata = tomllib.loads(project.read_text()) + return [ + requirement + for value in metadata["project"]["dependencies"] + if (requirement := Requirement(value)).name == "cryptography" + ] + + +@pytest.mark.parametrize( + ("system", "machine", "version", "accepted"), + [ + ("darwin", "x86_64", "48.0.1", True), + ("darwin", "x86_64", "49.0.0", False), + ("darwin", "x86_64", "50.0.2", False), + ("darwin", "arm64", "50.0.2", True), + ("linux", "x86_64", "50.0.2", True), + ("win32", "AMD64", "50.0.2", True), + ], +) +def test_published_metadata_prevents_unsupported_intel_builds( + system: str, machine: str, version: str, accepted: bool +) -> None: + bounds = _published_cryptography_bounds() + assert bounds, "uvx cannot see compatibility bounds in dependency groups" + environment = {"sys_platform": system, "platform_machine": machine} + active = [bound for bound in bounds if bound.marker.evaluate(environment)] + assert all(bound.specifier.contains(version) for bound in active) is accepted diff --git a/tests_py/scripts/test_codex_plugin_contract.py b/tests_py/scripts/test_codex_plugin_contract.py index 35089626..ca275f92 100644 --- a/tests_py/scripts/test_codex_plugin_contract.py +++ b/tests_py/scripts/test_codex_plugin_contract.py @@ -102,11 +102,10 @@ def test_codex_plugin_serves_the_full_profile_and_references_its_hooks() -> None assert (PLUGIN_ROOT / HOOKS_REF).resolve() == HOOKS_PATH.resolve() assert server == { - "command": "uvx", + "command": "python3", "args": [ - "--from", - f"hypermnesia-mcp[postgresql,sqlite]=={plugin['version']}", - "hypermnesia-mcp", + "${PLUGIN_ROOT}/scripts/runtime.py", + "server", ], # Codex's local storage selection has the same auto contract as the # DB-optional sandbox surface: try PostgreSQL first and fall back only @@ -139,7 +138,8 @@ def test_codex_plugin_ships_an_mcp_server_and_hooks_and_nothing_else() -> None: # installer script, and this one deliberately does not. # source: ADR-1084 (bundled stdlib intake, no installer script). assert {p.name for p in (PLUGIN_ROOT / "scripts").glob("*.py")} == { - "session_queue.py" + "session_queue.py", + "runtime.py", } diff --git a/tests_py/scripts/test_codex_plugin_hooks_contract.py b/tests_py/scripts/test_codex_plugin_hooks_contract.py index 6c88961d..8c2f06ab 100644 --- a/tests_py/scripts/test_codex_plugin_hooks_contract.py +++ b/tests_py/scripts/test_codex_plugin_hooks_contract.py @@ -14,8 +14,6 @@ from tests_py.scripts._codex_plugin_support import ( CLAUDE_SUFFIX, CODEX_SUFFIX, - PLUGIN_PATH, - read_json as _json, claude_hooks, codex_hooks, every_hook, @@ -68,9 +66,8 @@ def test_codex_hook_commands_run_the_published_wheel_not_this_repository() -> No if event == "SessionEnd": assert command == 'python3 "${PLUGIN_ROOT}/scripts/session_queue.py" intake' continue - assert "command -v uvx" in command - version = _json(PLUGIN_PATH)["version"] - assert f'uvx --from "hypermnesia-mcp[postgresql,sqlite]=={version}"' in command + assert 'python3 "${PLUGIN_ROOT}/scripts/runtime.py"' in command + assert "uvx" not in command def test_codex_hooks_use_only_codex_event_names() -> None: diff --git a/tests_py/scripts/test_codex_runtime.py b/tests_py/scripts/test_codex_runtime.py new file mode 100644 index 00000000..d8fd6013 --- /dev/null +++ b/tests_py/scripts/test_codex_runtime.py @@ -0,0 +1,96 @@ +"""No event-time dependency resolution. Source: native failure, 2026-10-02.""" + +import importlib.util +import os +from pathlib import Path +from unittest.mock import patch + +import pytest + +SCRIPT = ( + Path(__file__).resolve().parents[2] + / "plugins/hypermnesia-mcp-codex/scripts/runtime.py" +) +spec = importlib.util.spec_from_file_location("codex_runtime", SCRIPT) +runtime = importlib.util.module_from_spec(spec) +spec.loader.exec_module(runtime) + + +def installed(tmp_path, version): + root = tmp_path / "hypermnesia-mcp" + metadata = ( + root / f"lib/python3/site-packages/hypermnesia_mcp-{version}.dist-info/METADATA" + ) + metadata.parent.mkdir(parents=True) + metadata.write_text(f"Name: hypermnesia-mcp\nVersion: {version}\n") + python = root / ("Scripts/python.exe" if os.name == "nt" else "bin/python") + python.parent.mkdir(parents=True) + python.touch() + return python + + +def test_missing_runtime_fails_with_setup_instruction(tmp_path): + with patch.object(runtime.subprocess, "check_output", return_value=str(tmp_path)): + with pytest.raises(RuntimeError, match="setup"): + runtime.installed_python("4.23.5") + + +def test_wrong_version_refuses_stale_tool(tmp_path): + installed(tmp_path, "4.23.4") + with patch.object(runtime.subprocess, "check_output", return_value=str(tmp_path)): + with pytest.raises(RuntimeError, match="differs"): + runtime.installed_python("4.23.5") + + +def test_matching_runtime_execs_without_install_or_resolve(tmp_path): + python = installed(tmp_path, "4.23.5") + with ( + patch.object(runtime.sys, "argv", [str(SCRIPT), "post_tool_capture"]), + patch.object(runtime.subprocess, "check_output", return_value=str(tmp_path)), + patch.object(runtime.subprocess, "run") as run, + patch.object(runtime.os, "execv") as execute, + ): + runtime.main() + run.assert_not_called() + execute.assert_called_once() + assert execute.call_args.args[0] == str(python) + assert execute.call_args.args[1][-1] == "post_tool_capture" + assert execute.call_args.args[1][1] == "-I" + + +def test_setup_uses_host_interpreter_and_binary_wheels(): + with ( + patch.object(runtime.sys, "argv", [str(SCRIPT), "setup"]), + patch.object(runtime.subprocess, "run") as run, + patch.object(runtime, "installed_python"), + ): + runtime.main() + command = run.call_args.args[0] + assert command[:3] == ["uv", "tool", "install"] + assert command[command.index("--python") + 1] == runtime.sys.executable + assert "--no-build" in command + assert run.call_args.kwargs["check"] is True + + +def test_server_uses_the_same_isolated_interpreter(tmp_path): + python = installed(tmp_path, "4.23.5") + with ( + patch.object(runtime.sys, "argv", [str(SCRIPT), "server"]), + patch.object(runtime.subprocess, "check_output", return_value=str(tmp_path)), + patch.object(runtime.os, "execv") as execute, + ): + runtime.main() + execute.assert_called_once_with( + str(python), [str(python), "-I", "-m", "mcp_server"] + ) + + +def test_server_forwards_profile_arguments(tmp_path): + installed(tmp_path, "4.23.5") + with ( + patch.object(runtime.sys, "argv", [str(SCRIPT), "server", "--profile", "lean"]), + patch.object(runtime.subprocess, "check_output", return_value=str(tmp_path)), + patch.object(runtime.os, "execv") as execute, + ): + runtime.main() + assert execute.call_args.args[1][-2:] == ["--profile", "lean"] diff --git a/uv.lock b/uv.lock index e18a973c..d1ccf166 100644 --- a/uv.lock +++ b/uv.lock @@ -631,7 +631,7 @@ name = "coloredlogs" version = "15.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "humanfriendly" }, + { name = "humanfriendly", marker = "(python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine != 'arm64' and sys_platform == 'darwin') or (platform_release < '23' and sys_platform == 'darwin')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" } wheels = [ @@ -788,8 +788,8 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "cffi", marker = "platform_machine == 'x86_64' and platform_python_implementation != 'PyPy' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } wheels = [ @@ -842,8 +842,8 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "cffi", marker = "(platform_machine != 'x86_64' and platform_python_implementation != 'PyPy') or (platform_python_implementation != 'PyPy' and sys_platform != 'darwin')" }, + { name = "typing-extensions", marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz", hash = "sha256:5dd9bda1c12b4162f6ff568eeb5e0ff956c28d14406e875cfe8a63a2d414ff20", size = 880381, upload-time = "2026-08-25T19:45:45.499Z" } wheels = [ @@ -1229,8 +1229,8 @@ name = "httpcore2" version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "h11" }, - { name = "truststore" }, + { name = "h11", marker = "python_full_version < '3.11' or sys_platform != 'emscripten'" }, + { name = "truststore", marker = "python_full_version < '3.11' or sys_platform != 'emscripten'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/ad/f4f0e57345f1870f3e8cb624e058d7eca6e5a27d33bcc3311d9b618734cd/httpcore2-2.12.0.tar.gz", hash = "sha256:9293522bba0aa7c4c8e9e3f040c16575bd8868e155a77fa30c7a9085a5eae648", size = 67548, upload-time = "2026-08-18T13:22:08.211Z" } wheels = [ @@ -1291,14 +1291,14 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "hf-xet", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "packaging", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "pyyaml", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "requests", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "tqdm", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } wheels = [ @@ -1353,15 +1353,15 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "click" }, - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, - { name = "httpx" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "tqdm" }, - { name = "typing-extensions" }, + { name = "click", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "filelock", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "fsspec", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "hf-xet", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64') or platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or (platform_machine == 'x86_64' and sys_platform != 'darwin')" }, + { name = "httpx", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "packaging", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "pyyaml", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "tqdm", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/35/97/2eb4abaa5b969ed385066a0496a3823b3ff467fc1082e2202955f1867d60/huggingface_hub-1.30.0.tar.gz", hash = "sha256:e6a6120bc8c8e2723d03648434ee247088cceb55ba7067e7d34d692cad5fdb57", size = 964291, upload-time = "2026-09-03T10:05:14.053Z" } wheels = [ @@ -1373,7 +1373,7 @@ name = "humanfriendly" version = "10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyreadline3", marker = "sys_platform == 'win32'" }, + { name = "pyreadline3", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" } wheels = [ @@ -1386,6 +1386,7 @@ version = "4.23.5" source = { editable = "." } dependencies = [ { name = "anyio" }, + { name = "cryptography", version = "48.0.1", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, { name = "flashrank" }, { name = "mcp" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, @@ -1518,6 +1519,7 @@ typecheck = [ requires-dist = [ { name = "anyio", specifier = ">=4.5" }, { name = "cachetools", marker = "extra == 'viz-tile'", specifier = ">=5.0" }, + { name = "cryptography", marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'", specifier = "<49" }, { name = "datasets", marker = "extra == 'benchmarks'", specifier = ">=2.14.0" }, { name = "datashader", marker = "extra == 'viz-tile'", specifier = ">=0.16.3" }, { name = "exceptiongroup", marker = "extra == 'dev'", specifier = ">=1.2.0" }, @@ -1591,9 +1593,9 @@ platform-bounds = [ { name = "cryptography", marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'", specifier = "<49" }, { name = "numpy", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'", specifier = ">=2" }, { name = "numpy", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'", specifier = "<2" }, - { name = "onnxruntime", marker = "platform_release < '22' and sys_platform == 'darwin'", specifier = "<1.20" }, { name = "onnxruntime", marker = "platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin'", specifier = ">=1.20,<1.24" }, { name = "onnxruntime", marker = "platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", specifier = ">=1.20,<1.24" }, + { name = "onnxruntime", marker = "platform_release < '22' and sys_platform == 'darwin'", specifier = "<1.20" }, { name = "onnxruntime", marker = "(python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version >= '3.11' and sys_platform != 'darwin')", specifier = ">=1.24" }, { name = "torch", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')", specifier = ">=2.12" }, { name = "torch", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'", specifier = ">=2.4,<2.12" }, @@ -1643,7 +1645,7 @@ name = "importlib-metadata" version = "9.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } wheels = [ @@ -2562,15 +2564,15 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release < '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "coloredlogs" }, - { name = "flatbuffers" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine == 'arm64') or (python_full_version < '3.11' and platform_machine != 'x86_64' and platform_release < '22')" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*' and platform_machine != 'x86_64'" }, - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64')" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "sympy" }, + { name = "coloredlogs", marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_release < '22' and sys_platform == 'darwin')" }, + { name = "flatbuffers", marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_release < '22' and sys_platform == 'darwin')" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and platform_release < '22' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine != 'x86_64' and platform_release < '22' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and platform_machine == 'arm64' and platform_release < '22' and sys_platform == 'darwin')" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release < '22' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and platform_release < '22' and sys_platform == 'darwin')" }, + { name = "packaging", marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_release < '22' and sys_platform == 'darwin')" }, + { name = "protobuf", marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_release < '22' and sys_platform == 'darwin')" }, + { name = "sympy", marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_release < '22' and sys_platform == 'darwin')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/39/18/272d3d7406909141d3c9943796e3e97cafa53f4342d9231c0cfd8cb05702/onnxruntime-1.19.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:84fa57369c06cadd3c2a538ae2a26d76d583e7c34bdecd5769d71ca5c0fc750e", size = 16776408, upload-time = "2024-09-04T06:37:02.431Z" }, @@ -2598,15 +2600,15 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "coloredlogs" }, - { name = "flatbuffers" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine == 'arm64' and platform_release < '23') or (platform_machine != 'arm64' and platform_machine != 'x86_64') or (platform_machine == 'arm64' and platform_release >= '23') or sys_platform != 'darwin'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*' and platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin')" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "sympy" }, + { name = "coloredlogs", marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, + { name = "flatbuffers", marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*' and platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, + { name = "packaging", marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, + { name = "protobuf", marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, + { name = "sympy", marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version < '3.11' and sys_platform != 'darwin') or (platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/35/d6/311b1afea060015b56c742f3531168c1644650767f27ef40062569960587/onnxruntime-1.23.2-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a7730122afe186a784660f6ec5807138bf9d792fa1df76556b27307ea9ebcbe3", size = 17195934, upload-time = "2025-10-27T23:06:14.143Z" }, @@ -2659,11 +2661,11 @@ resolution-markers = [ "(python_full_version == '3.11.*' and platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'linux' and sys_platform != 'win32')", ] dependencies = [ - { name = "flatbuffers" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "packaging" }, - { name = "protobuf" }, + { name = "flatbuffers", marker = "(python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version >= '3.11' and sys_platform != 'darwin')" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, + { name = "packaging", marker = "(python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version >= '3.11' and sys_platform != 'darwin')" }, + { name = "protobuf", marker = "(python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release >= '23') or (python_full_version >= '3.11' and sys_platform != 'darwin')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/17/4d/5014667e2a3a77d6e1b74cc3d88948d06163b8e0a33a84c85073322b5dec/onnxruntime-1.28.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f5c5daabd28aad610f83fdcf32acec8fb57e6adc6c6a39fe2a3c755db957b410", size = 19130506, upload-time = "2026-07-25T01:22:34.489Z" }, @@ -2827,11 +2829,11 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "python-dateutil", marker = "python_full_version < '3.11'" }, + { name = "pytz", marker = "python_full_version < '3.11'" }, + { name = "tzdata", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ @@ -2930,11 +2932,11 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform != 'darwin')" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, - { name = "python-dateutil" }, - { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, + { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" } wheels = [ @@ -4397,11 +4399,11 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "joblib" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } }, - { name = "threadpoolctl" }, + { name = "joblib", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "threadpoolctl", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ @@ -4483,14 +4485,14 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "joblib" }, - { name = "narwhals" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform != 'darwin')" }, + { name = "joblib", marker = "python_full_version >= '3.11'" }, + { name = "narwhals", marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, - { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.12' and sys_platform != 'darwin')" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, - { name = "threadpoolctl" }, + { name = "threadpoolctl", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fa/6f/37092bdb25f712817231799fc5674d8e704066a8a70c1d2d40517e18b4ab/scikit_learn-1.9.0.tar.gz", hash = "sha256:8833266989d3a5110178a9fae30783675460724d0e1efb13b14901d2c660c557", size = 7750767, upload-time = "2026-06-02T11:54:32.706Z" } wheels = [ @@ -4541,8 +4543,8 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } wheels = [ @@ -4611,8 +4613,8 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ @@ -4713,7 +4715,7 @@ resolution-markers = [ "python_full_version == '3.12.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" } wheels = [ @@ -4772,17 +4774,17 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" } }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" } }, - { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" }, - { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" }, - { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" }, - { name = "tokenizers", version = "0.22.2", source = { registry = "https://pypi.org/simple" } }, - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" } }, - { name = "tqdm" }, - { name = "transformers", version = "4.57.6", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, + { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "tokenizers", version = "0.22.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "tqdm", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "transformers", version = "4.57.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9d/59/867381b1414a975da6c9953f48a07c05cb0629305e2d37c9bcc9764367b2/sentence_transformers-5.7.0.tar.gz", hash = "sha256:fd8c8fc35e6323631dff9f3760969ebf7980dc3cfda0ab1354bc6a774cc0e5d8", size = 466382, upload-time = "2026-08-06T12:12:33.371Z" } wheels = [ @@ -4837,22 +4839,22 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" } }, + { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin')" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, - { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and platform_machine != 'x86_64') or (python_full_version >= '3.11' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin')" }, + { name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform != 'darwin')" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, - { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin')" }, - { name = "tokenizers", version = "0.23.2", source = { registry = "https://pypi.org/simple" } }, + { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, + { name = "tokenizers", version = "0.23.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "torch", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, - { name = "torch", version = "2.13.0", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'arm64' and sys_platform == 'darwin') or (platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "torch", version = "2.13.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "torch", version = "2.13.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "sys_platform == 'linux'" }, - { name = "tqdm" }, - { name = "transformers", version = "5.16.1", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, + { name = "tqdm", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "transformers", version = "5.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/ef/87681678d0aa91a1e77f0ffdd2e5d900aaf358aac644dd14bead8d95ec4c/sentence_transformers-6.0.1.tar.gz", hash = "sha256:1c3b8d9403f87ad0c879638554f36cc85744f38a6a70d150fd7e964ca0e9935b", size = 575395, upload-time = "2026-08-31T07:50:43.518Z" } wheels = [ @@ -5128,7 +5130,7 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" } }, + { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } wheels = [ @@ -5183,7 +5185,7 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" } }, + { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz", hash = "sha256:7f0f085686b9de0d0079e6f874ae053600db64c5d13049e0bbc0119926d25aac", size = 385745, upload-time = "2026-09-03T08:55:42.89Z" } wheels = [ @@ -5299,13 +5301,13 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "jinja2", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "sympy", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/3b/55/7192974ab13e5e5577f45d14ce70d42f5a9a686b4f57bbe8c9ab45c4a61a/torch-2.2.2-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b2e2200b245bd9f263a0d41b6a2dab69c4aca635a01b30cca78064b0ef5b109e", size = 150788930, upload-time = "2024-03-27T21:08:09.98Z" }, @@ -5330,14 +5332,14 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '22' and platform_release < '23' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "setuptools", version = "81.0.0", source = { registry = "https://pypi.org/simple" } }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "jinja2", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "setuptools", version = "81.0.0", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "sympy", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "platform_machine == 'arm64' and platform_release < '23' and sys_platform == 'darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ac/f2/c1690994afe461aae2d0cac62251e6802a703dec0a6c549c02ecd0de92a9/torch-2.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2c0d7fcfbc0c4e8bb5ebc3907cbc0c6a0da1b8f82b1fc6e14e914fa0b9baf74e", size = 80526521, upload-time = "2026-03-23T18:12:06.86Z" }, @@ -5379,14 +5381,14 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and platform_machine != 'x86_64') or (python_full_version >= '3.11' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin')" }, - { name = "setuptools", version = "84.0.0", source = { registry = "https://pypi.org/simple" } }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "fsspec", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "jinja2", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.11' and platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "setuptools", version = "84.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "sympy", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "typing-extensions", marker = "(python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release >= '23' and sys_platform == 'darwin') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/7f/e7/19894fdb51c7dbaf94f5a79bb0871da0992e8e4241e579cb006da46d2e58/torch-2.13.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:94f0de129916f77b8dc2c7a8eff644cfeddfe59e39c9f55e9f6e17543410281d", size = 111178962, upload-time = "2026-07-08T16:05:49.855Z" }, @@ -5418,14 +5420,14 @@ resolution-markers = [ "python_full_version < '3.11' and sys_platform == 'linux'", ] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "setuptools", version = "84.0.0", source = { registry = "https://pypi.org/simple" } }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "sys_platform == 'linux'" }, + { name = "fsspec", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and sys_platform == 'linux'" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and sys_platform == 'linux'" }, + { name = "setuptools", version = "84.0.0", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform == 'linux'" }, + { name = "sympy", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.13.0%2Bcpu-cp310-cp310-linux_s390x.whl", hash = "sha256:0555fde6108ca90247ae33d4e1237cbae475c86a223bb2f0f91d9addf1f611bd", upload-time = "2026-07-08T19:27:11Z" }, @@ -5477,16 +5479,16 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock" }, - { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" } }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "regex" }, - { name = "requests" }, - { name = "safetensors" }, - { name = "tokenizers", version = "0.22.2", source = { registry = "https://pypi.org/simple" } }, - { name = "tqdm" }, + { name = "filelock", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "huggingface-hub", version = "0.36.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "packaging", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "pyyaml", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "regex", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "requests", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "safetensors", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "tokenizers", version = "0.22.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "tqdm", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" } wheels = [ @@ -5541,17 +5543,17 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" } }, + { name = "huggingface-hub", version = "1.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'darwin')" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "regex" }, - { name = "safetensors" }, - { name = "tokenizers", version = "0.23.2", source = { registry = "https://pypi.org/simple" } }, - { name = "tqdm" }, - { name = "typer" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, + { name = "packaging", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "pyyaml", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "regex", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "safetensors", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "tokenizers", version = "0.23.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "tqdm", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "typer", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/2e/ba418680ab901dae269360bb8642485eae04f1af91ee2ebb8bd6f3607305/transformers-5.16.1.tar.gz", hash = "sha256:17b0eac726ddc55e84ac58946063e0c6d37fd000c456b581f050ea0f4e822869", size = 9650542, upload-time = "2026-08-26T14:48:58.789Z" } wheels = [ @@ -5646,10 +5648,10 @@ name = "typer" version = "0.27.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "annotated-doc" }, + { name = "annotated-doc", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "rich" }, - { name = "shellingham" }, + { name = "rich", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "shellingham", marker = "python_full_version >= '3.13' or platform_machine != 'x86_64' or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/16/f7/57713ba479fd405eb76de31404b2c744c289e336b2d999511ebf51e496f7/typer-0.27.2.tar.gz", hash = "sha256:269b7eb9d3c202ca84b4bc9618cb04ebb43d3d4d1e567e4c768607232c05f945", size = 204045, upload-time = "2026-08-28T10:26:55.046Z" } wheels = [ @@ -5709,8 +5711,8 @@ name = "uvicorn" version = "0.52.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "h11" }, + { name = "click", marker = "python_full_version < '3.11' or sys_platform != 'emscripten'" }, + { name = "h11", marker = "python_full_version < '3.11' or sys_platform != 'emscripten'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f2/0f/3f86e61397dd33bf2ccf28188c40db6a740658aeebbbf6e7dbc101a1f487/uvicorn-0.52.4.tar.gz", hash = "sha256:73acfee47a0b133c5de13d219492d62d8a31e935f4fe6e41a232451a15379f86", size = 100627, upload-time = "2026-08-19T06:27:41.821Z" } @@ -5733,10 +5735,10 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine != 'arm64' and platform_machine != 'x86_64' and platform_release >= '22' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, - { name = "packaging" }, - { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and platform_machine != 'x86_64') or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/ec/e50d833518f10b0c24feb184b209bb6856f25b919ba8c1f89678b930b1cd/xarray-2025.6.1.tar.gz", hash = "sha256:a84f3f07544634a130d7dc615ae44175419f4c77957a7255161ed99c69c7c8b0", size = 3003185, upload-time = "2025-06-12T03:04:09.099Z" } wheels = [ @@ -5789,11 +5791,11 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine != 'arm64' and platform_machine != 'x86_64' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform != 'darwin')" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version == '3.11.*' and platform_machine != 'x86_64') or (python_full_version == '3.11.*' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin')" }, - { name = "packaging" }, - { name = "pandas", version = "3.0.5", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pandas", version = "3.0.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ea/96/3f7bdd00e505ec3698903415b30135024703e017b28c6b61f98da3193b0d/xarray-2026.7.0.tar.gz", hash = "sha256:361b495928fdbf5b58d0969bb6775339019da5e93ca74d61ddf4eb5edd6ce604", size = 3145348, upload-time = "2026-07-09T17:38:26.515Z" } wheels = [