Răsfoiți Sursa

feat(python): support macOS x64 runtime wheels

fz 1 săptămână în urmă
părinte
comite
7dcdcc2965

+ 2 - 2
.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md
-2026-07-10-single-file-executable-sdk-runtime-distribution.md: ab09691b48684b8ebae269df4d585b499423e671
-2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md: d986105b087357bd8301251dca14736a5b427bbb
+2026-07-10-single-file-executable-sdk-runtime-distribution.md: 3f8f11c4b9d8ece425ed737bdfdf962315412216
+2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md: de0d011b9e7a2a52748ac273d5f0bbb7dce27894

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md


+ 22 - 10
.github/workflows/build-exe-for-python-sdk.yml

@@ -2,7 +2,7 @@ name: Build single-exe
 
 # Native builds for the release targets; see
 # .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md.
-# A full target run retains one SDK wheel and four runtime wheels; subset
+# A full target run retains one SDK wheel and five runtime wheels; subset
 # dispatch retains the SDK wheel and selected runtime wheels. Bare executables
 # and source closures are test inputs. Run manually or call it from the Python
 # release workflow. There is no `pull_request` trigger: a label trigger would
@@ -12,7 +12,7 @@ on:
   workflow_call:
     inputs:
       targets:
-        description: Comma-separated pkg targets to build; empty builds all four.
+        description: Comma-separated pkg targets to build; empty builds all five.
         type: string
         required: false
         default: ''
@@ -36,7 +36,7 @@ on:
         description: >-
           Comma-separated pkg targets to build. Any subset of:
           node24-linux-x64, node24-linux-arm64, node24-macos-arm64,
-          node24-win-x64. Empty builds all four.
+          node24-macos-x64, node24-win-x64. Empty builds all five.
         type: string
         required: false
         default: ''
@@ -89,7 +89,7 @@ jobs:
         id: plan
         env:
           # Blank dispatch inputs build all targets.
-          TARGETS: ${{ inputs.targets || 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64' }}
+          TARGETS: ${{ inputs.targets || 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64' }}
         run: |
           set -euo pipefail
           matrix='[]'
@@ -98,14 +98,15 @@ jobs:
             t="$(echo "$raw" | xargs)" # trim surrounding whitespace
             [ -z "$t" ] && continue
             # Native-only: hosted arm64 Linux uses ubuntu-24.04-arm, while
-            # macos-latest is Apple Silicon.
+            # macos-latest is Apple Silicon; macos-15-intel is native x64.
             case "$t" in
               node24-linux-x64)   runner=ubuntu-latest ;;
               node24-linux-arm64) runner=ubuntu-24.04-arm ;;
               node24-macos-arm64) runner=macos-latest ;;
+              node24-macos-x64)   runner=macos-15-intel ;;
               node24-win-x64)     runner=windows-2025 ;;
               *)
-                echo "::error::Unknown target '$t'. Supported: node24-linux-x64, node24-linux-arm64, node24-macos-arm64, node24-win-x64."
+                echo "::error::Unknown target '$t'. Supported: node24-linux-x64, node24-linux-arm64, node24-macos-arm64, node24-macos-x64, node24-win-x64."
                 exit 1
                 ;;
             esac
@@ -251,6 +252,7 @@ jobs:
             linux-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl ;;
             linux-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl ;;
             macos-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl ;;
+            macos-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_x86_64.whl ;;
             *) echo "::error::Unsupported runtime platform $platform"; exit 1 ;;
           esac
           [ -x "$exe" ] || { echo "::error::$exe missing or not executable"; exit 1; }
@@ -432,13 +434,23 @@ jobs:
             exit 1
           }
 
-      - name: Check macOS deployment target
+      - name: Check macOS payload architecture and deployment target
         if: runner.os == 'macOS'
         env:
           EXE: ${{ steps.runtime-posix.outputs.exe }}
-        run: >-
-          python3 scripts/check-macos-deployment-target.py
-          "$EXE" "$EXE-spawn-helper"
+          PLATFORM: ${{ steps.runtime-posix.outputs.platform }}
+        run: |
+          set -euo pipefail
+          case "$PLATFORM" in
+            macos-arm64) macho_arch=arm64 ;;
+            macos-x64) macho_arch=x86_64 ;;
+            *) echo "::error::Unsupported macOS platform $PLATFORM"; exit 1 ;;
+          esac
+          for payload in "$EXE" "$EXE-rg" "$EXE-spawn-helper"; do
+            lipo "$payload" -verify_arch "$macho_arch"
+          done
+          python3 scripts/check-macos-deployment-target.py \
+            --platform "$PLATFORM" "$EXE" "$EXE-rg" "$EXE-spawn-helper"
 
       - name: Run wheel in a manylinux 2.28 container
         if: runner.os == 'Linux'

+ 1 - 1
.github/workflows/ci.yml

@@ -328,7 +328,7 @@ jobs:
     name: python runtime / release-shaped matrix
     uses: ./.github/workflows/build-exe-for-python-sdk.yml
     with:
-      targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64
+      targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64
       ci: true
     secrets:
       DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}

+ 3 - 2
.github/workflows/python-release.yml

@@ -24,10 +24,10 @@ concurrency:
 
 jobs:
   build:
-    name: Build five wheels
+    name: Build six wheels
     uses: ./.github/workflows/build-exe-for-python-sdk.yml
     with:
-      targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64
+      targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64
       release: true
 
   python-compat:
@@ -149,6 +149,7 @@ jobs:
           actual="$(mktemp)"
           printf '%s\n' \
             "deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl" \
+            "deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_x86_64.whl" \
             "deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl" \
             "deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl" \
             "deepseek_harness_runtime_bin-$VERSION-py3-none-win_amd64.whl" \

+ 24 - 3
.gitlab-ci.yml

@@ -60,8 +60,16 @@ sdk-wheel:
         docker run --rm -v "$PWD:/work" -w /work "$image" bash -euxo pipefail -c "/opt/python/cp310-cp310/bin/python -m venv /tmp/dsh-sdk && /tmp/dsh-sdk/bin/python -m pip install --find-links /work/release/$PLATFORM --find-links /work/release/sdk deepseek-harness-sdk==$DSH_WHEEL_VERSION && /tmp/dsh-sdk/bin/python /work/scripts/smoke-python-runtime.py --scenario sdk-default && /tmp/dsh-sdk/bin/python /work/scripts/smoke-python-runtime.py --scenario sdk-mcp"
       fi
     - |
-      if [ "$PLATFORM" = macos-arm64 ]; then
-        python3 scripts/check-macos-deployment-target.py "$EXE" "$EXE-spawn-helper"
+      if [ "${PLATFORM#macos-}" != "$PLATFORM" ]; then
+        case "$PLATFORM" in
+          macos-arm64) macho_arch=arm64 ;;
+          macos-x64) macho_arch=x86_64 ;;
+          *) echo "Unsupported macOS platform $PLATFORM"; exit 1 ;;
+        esac
+        for payload in "$EXE" "$EXE-rg" "$EXE-spawn-helper"; do
+          lipo "$payload" -verify_arch "$macho_arch"
+        done
+        python3 scripts/check-macos-deployment-target.py --platform "$PLATFORM" "$EXE" "$EXE-rg" "$EXE-spawn-helper"
       fi
   artifacts:
     paths: [release/$PLATFORM/*.whl]
@@ -97,6 +105,16 @@ runtime-macos-arm64:
     - job: sdk-wheel
       artifacts: true
 
+runtime-macos-x64:
+  extends: .runtime-wheel
+  tags: [macos-x64]
+  variables:
+    PKG_TARGET: node24-macos-x64
+    PLATFORM: macos-x64
+  needs:
+    - job: sdk-wheel
+      artifacts: true
+
 runtime-windows-x64:
   stage: build
   tags: [windows-x64]
@@ -147,6 +165,8 @@ publish-python:
       artifacts: true
     - job: runtime-macos-arm64
       artifacts: true
+    - job: runtime-macos-x64
+      artifacts: true
     - job: runtime-windows-x64
       artifacts: true
   before_script:
@@ -157,11 +177,12 @@ publish-python:
     - test "$CI_COMMIT_TAG" = "python-v$DSH_VERSION" || { echo "Tag $CI_COMMIT_TAG does not match package.json version $DSH_VERSION"; exit 1; }
     - python -m pip install twine==6.2.0
   script:
-    - test "$(find release -name '*.whl' | wc -l | tr -d ' ')" = 5
+    - test "$(find release -name '*.whl' | wc -l | tr -d ' ')" = 6
     - test -f "release/sdk/deepseek_harness_sdk-${DSH_WHEEL_VERSION}-py3-none-any.whl"
     - test -f "release/linux-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_x86_64.whl"
     - test -f "release/linux-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_aarch64.whl"
     - test -f "release/macos-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-macosx_14_0_arm64.whl"
+    - test -f "release/macos-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-macosx_14_0_x86_64.whl"
     - test -f "release/win-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-win_amd64.whl"
     - python -m twine check release/*/*.whl
     - export TWINE_USERNAME=gitlab-ci-token

+ 2 - 2
python/development.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write python/development.md
-development.md: 72acaec2b3ec2142fc176d940f1a2854e44ebad8
-development.zh.md: 8bd17ad7e604b1cdc4456053bcec95c9e8e503cb
+development.md: aa0144d7eaa66711d0f08316d4445da060918ca8
+development.zh.md: a35f6fc8de1bdbd282fd8999a1440fde0c400b34

+ 3 - 3
python/development.md

@@ -13,7 +13,7 @@ pnpm install
 pnpm exec tsx scripts/build-exe-for-python-sdk.ts
 ```
 
-Use `--skip-build` when the required `lib/` artifacts already exist, or `--targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64` to select platforms. Build each target on its native architecture. Products land in `dist-exe/` and the script syncs the selected carriers into `python/sdk-runtime/`. Windows emits `.exe` and `-rg.exe`; macOS also syncs the matching spawn helper required by `node-pty`.
+Use `--skip-build` when the required `lib/` artifacts already exist, or `--targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64` to select platforms. Build each target on its native architecture. Products land in `dist-exe/` and the script syncs the selected carriers into `python/sdk-runtime/`. Windows emits `.exe` and `-rg.exe`; macOS also syncs the matching spawn helper required by `node-pty`.
 
 ## Validate the SDK
 
@@ -79,11 +79,11 @@ pip install \
   "dist-python/deepseek_harness_runtime_bin-$version-py3-none-macosx_14_0_arm64.whl"
 ```
 
-The runtime distribution is wheel-only. The release pipeline publishes four platform wheels with the pure SDK wheel: Linux x64, Linux arm64, macOS 14 or newer on arm64, and Windows x64 (`win_amd64`). A `python-v<repository-version>` tag is accepted only when it matches the repository version; prerelease repository versions such as `0.0.1-rc.1` use their normalized PEP 440 spelling, such as `0.0.1rc1`, inside wheel filenames and metadata.
+The runtime distribution is wheel-only. The release pipeline publishes five platform wheels with the pure SDK wheel: Linux x64, Linux arm64, macOS 14 or newer on arm64 and x64, and Windows x64 (`win_amd64`). A `python-v<repository-version>` tag is accepted only when it matches the repository version; prerelease repository versions such as `0.0.1-rc.1` use their normalized PEP 440 spelling, such as `0.0.1rc1`, inside wheel filenames and metadata.
 
 ## Validate a release candidate
 
-Manually run the GitHub `Release (Python)` workflow with `publish=false` to build all five wheels, install the Linux release set on Python 3.10 and 3.14, check exact filenames and metadata, enforce PyPI's default per-file size limit, and retain one aggregate artifact with SHA-256 hashes. The run has no registry credentials; a dry run cannot enter either publication job.
+Manually run the GitHub `Release (Python)` workflow with `publish=false` to build all six wheels, install the Linux release set on Python 3.10 and 3.14, check exact filenames and metadata, enforce PyPI's default per-file size limit, and retain one aggregate artifact with SHA-256 hashes. The run has no registry credentials; a dry run cannot enter either publication job.
 
 Public publication runs from the private automation repository. Package metadata points to the separate read-only public source mirror, which does not run release Actions. The private repository defines the repository variable `PYPI_PUBLISHER_REPOSITORY` as its own `owner/name` and keeps `PUBLIC_PYPI_RELEASE_ENABLED=false` except during an intentional release.
 

+ 3 - 3
python/development.zh.md

@@ -13,7 +13,7 @@ pnpm install
 pnpm exec tsx scripts/build-exe-for-python-sdk.ts
 ```
 
-所需 `lib/` 产物已存在时使用 `--skip-build`;如需选择平台,请使用 `--targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64`。每个目标都应在其原生架构上构建。产物写入 `dist-exe/`,脚本会将所选载体同步到 `python/sdk-runtime/`。Windows 会生成 `.exe` 与 `-rg.exe`;macOS 构建还会同步 `node-pty` 所需的配套 spawn 辅助程序。
+所需 `lib/` 产物已存在时使用 `--skip-build`;如需选择平台,请使用 `--targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64`。每个目标都应在其原生架构上构建。产物写入 `dist-exe/`,脚本会将所选载体同步到 `python/sdk-runtime/`。Windows 会生成 `.exe` 与 `-rg.exe`;macOS 构建还会同步 `node-pty` 所需的配套 spawn 辅助程序。
 
 ## 验证 SDK
 
@@ -79,11 +79,11 @@ pip install \
   "dist-python/deepseek_harness_runtime_bin-$version-py3-none-macosx_14_0_arm64.whl"
 ```
 
-运行时分发包仅提供 wheel 包。发布流水线会连同纯 SDK wheel 包一起发布个平台 wheel 包:Linux x64、Linux arm64、macOS 14 或更高版本的 arm64,以及 Windows x64(`win_amd64`)。只有与仓库版本匹配时,才接受 `python-v<repository-version>` 标签;`0.0.1-rc.1` 之类的仓库预发布版本在 wheel 包文件名和元数据中使用规范化的 PEP 440 写法,例如 `0.0.1rc1`。
+运行时分发包仅提供 wheel 包。发布流水线会连同纯 SDK wheel 包一起发布个平台 wheel 包:Linux x64、Linux arm64、macOS 14 或更高版本的 arm64 与 x64,以及 Windows x64(`win_amd64`)。只有与仓库版本匹配时,才接受 `python-v<repository-version>` 标签;`0.0.1-rc.1` 之类的仓库预发布版本在 wheel 包文件名和元数据中使用规范化的 PEP 440 写法,例如 `0.0.1rc1`。
 
 ## 验证候选发行版
 
-手动运行 GitHub 的 `Release (Python)` 工作流并设置 `publish=false`,即可构建全部个 wheel 包,在 Python 3.10 和 3.14 上安装 Linux 发行集合,检查精确文件名和元数据,执行 PyPI 默认单文件大小限制,并保留一份带 SHA-256 哈希的汇总产物。该运行没有注册表凭据,dry-run 运行无法进入任何发布作业。
+手动运行 GitHub 的 `Release (Python)` 工作流并设置 `publish=false`,即可构建全部个 wheel 包,在 Python 3.10 和 3.14 上安装 Linux 发行集合,检查精确文件名和元数据,执行 PyPI 默认单文件大小限制,并保留一份带 SHA-256 哈希的汇总产物。该运行没有注册表凭据,dry-run 运行无法进入任何发布作业。
 
 公开发布从私有自动化仓库运行。包元数据指向独立的只读公开源码镜像,该镜像不运行发布 Actions。私有仓库把仓库变量 `PYPI_PUBLISHER_REPOSITORY` 定义为自身的 `owner/name`,并且只在有意发布期间把 `PUBLIC_PYPI_RELEASE_ENABLED` 从 `false` 改为 `true`。
 

+ 2 - 2
python/sdk-runtime/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write python/sdk-runtime/README.md
-README.md: 28695259928a7edc6e6cf67e737f1012729df5a4
-README.zh.md: f23b253cfe47d9f1ae24568b51d9db810c7a4a9f
+README.md: 050ae85d9b0a38b82a3c66a84c3d8f34e137be6c
+README.zh.md: 7066d7224752294c25b58cfe8fb6a94524a2013d

+ 1 - 1
python/sdk-runtime/README.md

@@ -8,7 +8,7 @@ Platform runtime wheel for the DeepSeek Harness Python SDK. It packages the norm
 
 The wheel installs a `dsh` console command and the `deepseek_harness_runtime` Python module. `dsh` forwards its arguments to the bundled executable and requires a non-empty `DSH_HOME`; it never falls back to `~/.dsh`.
 
-Production executables are named `deepseek-harness-sdk-runtime-<platform>-<arch>` under the module's `runtime/` directory; Windows uses the `.exe` suffix. Linux and macOS wheels include a target-native `-rg` sidecar, Windows includes `-rg.exe`, and macOS also includes `-spawn-helper` for `node-pty`. Published targets are Linux x64, Linux arm64, macOS arm64, and Windows x64. The wheel tag and payload must match exactly; no Windows arm64 wheel is published.
+Production executables are named `deepseek-harness-sdk-runtime-<platform>-<arch>` under the module's `runtime/` directory; Windows uses the `.exe` suffix. Linux and macOS wheels include a target-native `-rg` sidecar, Windows includes `-rg.exe`, and macOS also includes `-spawn-helper` for `node-pty`. Published targets are Linux x64, Linux arm64, macOS arm64, macOS x64, and Windows x64. The wheel tag and payload must match exactly; no Windows arm64 wheel is published.
 
 Repository builds also materialize a dev-only `runtime/node/` carrier. It runs `node runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js` on system Node 22.19 or newer. It is never selected automatically and is excluded from wheels and sdists.
 

+ 1 - 1
python/sdk-runtime/README.zh.md

@@ -8,7 +8,7 @@ DeepSeek Harness Python SDK 的平台运行时 wheel。它把普通 `dsh` CLI 
 
 Wheel 会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python 模块。`dsh` 将参数转发给内置可执行程序,并要求非空 `DSH_HOME`;它不会回退到 `~/.dsh`。
 
-生产可执行程序位于模块的 `runtime/` 目录,命名为 `deepseek-harness-sdk-runtime-<platform>-<arch>`;Windows 使用 `.exe` 后缀。Linux 与 macOS wheel 包含目标平台原生的 `-rg` 伴随程序,Windows 包含 `-rg.exe`,macOS 还包含 `node-pty` 使用的 `-spawn-helper`。已发布目标是 Linux x64、Linux arm64、macOS arm64 与 Windows x64。Wheel tag 必须与载荷严格匹配;不发布 Windows arm64 wheel。
+生产可执行程序位于模块的 `runtime/` 目录,命名为 `deepseek-harness-sdk-runtime-<platform>-<arch>`;Windows 使用 `.exe` 后缀。Linux 与 macOS wheel 包含目标平台原生的 `-rg` 伴随程序,Windows 包含 `-rg.exe`,macOS 还包含 `node-pty` 使用的 `-spawn-helper`。已发布目标是 Linux x64、Linux arm64、macOS arm64、macOS x64 与 Windows x64。Wheel tag 必须与载荷严格匹配;不发布 Windows arm64 wheel。
 
 仓库构建还会物化仅限开发的 `runtime/node/` 载体。它在系统 Node 22.19 或更高版本上运行 `node runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js`。系统不会自动选择它,而且 wheel 与 sdist 均不包含它。
 

+ 4 - 0
python/sdk-runtime/platforms.json

@@ -11,6 +11,10 @@
     "tag": "macosx_14_0_arm64",
     "executable": "deepseek-harness-sdk-runtime-macos-arm64"
   },
+  "macos-x64": {
+    "tag": "macosx_14_0_x86_64",
+    "executable": "deepseek-harness-sdk-runtime-macos-x64"
+  },
   "win-x64": {
     "tag": "win_amd64",
     "executable": "deepseek-harness-sdk-runtime-win-x64.exe"

+ 1 - 2
python/sdk-runtime/src/deepseek_harness_runtime/__init__.py

@@ -120,12 +120,11 @@ def _current_platform_tag() -> str:
         plat is None
         or arch is None
         or (plat == "win" and arch != "x64")
-        or (plat == "macos" and arch != "arm64")
     ):
         raise FileNotFoundError(
             "no bundled DeepSeek Harness SDK runtime exists for this platform "
             f"(sys.platform={sys.platform!r}, machine={platform.machine()!r}); supported: "
-            "Linux x64/arm64, macOS arm64, and Windows x64. " + _EXE_ACQUISITION_HINT
+            "Linux x64/arm64, macOS x64/arm64, and Windows x64. " + _EXE_ACQUISITION_HINT
         )
     return f"{plat}-{arch}"
 

+ 30 - 1
python/sdk/tests/test_macos_deployment_target.py

@@ -16,8 +16,15 @@ checker = SimpleNamespace(**runpy.run_path(str(SCRIPT)))
 
 def test_otool_parser_uses_the_newest_macho_slice() -> None:
     output = """
+Load command 8
+      cmd LC_VERSION_MIN_MACOSX
+  cmdsize 16
+  version 10.7
+      sdk 11.1
+Load command 9
       cmd LC_BUILD_VERSION
     minos 11.0
+Load command 10
       cmd LC_BUILD_VERSION
     minos 13.5
     """
@@ -26,12 +33,34 @@ def test_otool_parser_uses_the_newest_macho_slice() -> None:
 
 
 def test_otool_parser_requires_a_deployment_target() -> None:
-    with pytest.raises(ValueError, match="contains no LC_BUILD_VERSION"):
+    with pytest.raises(ValueError, match="contains no macOS deployment target"):
         checker.parse_otool_deployment_target("Load command 0\n")
 
 
+def test_otool_parser_ignores_unrelated_version_fields() -> None:
+    output = """
+Load command 1
+          cmd LC_ID_DYLIB
+      cmdsize 48
+      current version 14.1.0
+compatibility version 1.0.0
+    """
+
+    with pytest.raises(ValueError, match="contains no macOS deployment target"):
+        checker.parse_otool_deployment_target(output)
+
+
 def test_wheel_tag_rejects_a_newer_executable_target() -> None:
     checker.ensure_compatible(Path("runtime"), (13, 5), "macosx_14_0_arm64")
+    checker.ensure_compatible(Path("runtime-x64"), (10, 7), "macosx_14_0_x86_64")
 
     with pytest.raises(RuntimeError, match="requires macOS 14.1"):
         checker.ensure_compatible(Path("spawn-helper"), (14, 1), "macosx_14_0_arm64")
+
+
+def test_wheel_tag_accepts_only_supported_macos_architectures() -> None:
+    assert checker.claimed_version("macosx_14_0_arm64") == (14, 0)
+    assert checker.claimed_version("macosx_14_0_x86_64") == (14, 0)
+
+    with pytest.raises(ValueError, match="unsupported macOS wheel platform tag"):
+        checker.claimed_version("macosx_14_0_universal2")

+ 3 - 1
python/sdk/tests/test_release_version.py

@@ -60,6 +60,8 @@ def test_pep440_version_spells_a_prerelease_the_python_way() -> None:
 def test_macos_wheel_tag_does_not_claim_unsupported_node_platforms() -> None:
     assert build_python_release.PLATFORMS["macos-arm64"][0] == "macosx_14_0_arm64"
     assert build_python_release.PLATFORMS["macos-arm64"][1] == "deepseek-harness-sdk-runtime-macos-arm64"
+    assert build_python_release.PLATFORMS["macos-x64"][0] == "macosx_14_0_x86_64"
+    assert build_python_release.PLATFORMS["macos-x64"][1] == "deepseek-harness-sdk-runtime-macos-x64"
 
 
 def test_windows_wheel_tag_and_payload_are_x64_only() -> None:
@@ -95,7 +97,7 @@ def test_stage_sdk_keeps_distribution_module_and_runtime_pin_distinct(tmp_path:
 
 @pytest.mark.parametrize(
     ("target", "with_helper"),
-    [("linux-x64", False), ("macos-arm64", True), ("win-x64.exe", False)],
+    [("linux-x64", False), ("macos-arm64", True), ("macos-x64", True), ("win-x64.exe", False)],
 )
 def test_stage_runtime_copies_platform_payload(
     tmp_path: Path, target: str, with_helper: bool

+ 2 - 3
python/sdk/tests/test_runtime_resolution.py

@@ -79,12 +79,11 @@ def test_current_platform_supports_windows_x64_only(monkeypatch: pytest.MonkeyPa
         runtime._current_platform_tag()
 
 
-def test_current_platform_rejects_macos_x64(monkeypatch: pytest.MonkeyPatch) -> None:
+def test_current_platform_supports_macos_x64(monkeypatch: pytest.MonkeyPatch) -> None:
     monkeypatch.setattr(runtime.sys, "platform", "darwin")
     monkeypatch.setattr(runtime.platform, "machine", lambda: "x86_64")
 
-    with pytest.raises(FileNotFoundError, match="macOS arm64"):
-        runtime._current_platform_tag()
+    assert runtime._current_platform_tag() == "macos-x64"
 
 
 def test_runtime_requires_ripgrep_sidecar(

+ 13 - 0
scripts/build-exe-for-python-sdk.spec.ts

@@ -59,6 +59,19 @@ describe('Python runtime executable builder CLI', () => {
     expect(result.stdout).not.toMatch(/pnpm\.cmd/i)
   })
 
+  it('accepts the macOS x64 pkg target', () => {
+    const result = run(
+      { npm_execpath: 'C:\\tools\\pnpm.cjs' },
+      '--skip-build',
+      '--dry-run',
+      '--targets=node24-macos-x64',
+    )
+
+    expect(result.status).toBe(0)
+    expect(result.stdout).toContain('exec pkg')
+    expect(result.stdout).toContain('--sea --targets node24-macos-x64')
+  })
+
   it('rejects a Windows arm64 product before any build step', () => {
     const result = run(
       { npm_execpath: 'C:\\tools\\pnpm.cjs' },

+ 1 - 1
scripts/build-exe-for-python-sdk.ts

@@ -207,7 +207,7 @@ class BuildCli {
     return [
       'Usage: pnpm exec tsx scripts/build-exe-for-python-sdk.ts [flags]',
       '',
-      '  --targets=<t1,t2,...>  pkg targets, e.g. node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64.',
+      '  --targets=<t1,t2,...>  pkg targets, e.g. node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64.',
       '                         Default: the host platform only (on node24).',
       '  --skip-build           skip `pnpm run build` (lib/ artifacts must already exist).',
       '  --dry-run              print every command and config patch without executing.',

+ 26 - 10
scripts/check-macos-deployment-target.py

@@ -12,7 +12,11 @@ from pathlib import Path
 
 ROOT = Path(__file__).resolve().parents[1]
 RELEASE = runpy.run_path(str(ROOT / "scripts" / "build-python-release.py"))
-MACOS_PLATFORM_TAG = RELEASE["PLATFORMS"]["macos-arm64"][0]
+MACOS_PLATFORMS = {
+    name: details[0]
+    for name, details in RELEASE["PLATFORMS"].items()
+    if name.startswith("macos-")
+}
 
 
 def parse_version(value: str) -> tuple[int, ...]:
@@ -24,7 +28,7 @@ def parse_version(value: str) -> tuple[int, ...]:
 
 def claimed_version(platform_tag: str) -> tuple[int, ...]:
     """Return the minimum macOS version encoded by a wheel platform tag."""
-    match = re.fullmatch(r"macosx_(\d+)_(\d+)_arm64", platform_tag)
+    match = re.fullmatch(r"macosx_(\d+)_(\d+)_(?:arm64|x86_64)", platform_tag)
     if match is None:
         raise ValueError(f"unsupported macOS wheel platform tag: {platform_tag!r}")
     return int(match.group(1)), int(match.group(2))
@@ -32,12 +36,22 @@ def claimed_version(platform_tag: str) -> tuple[int, ...]:
 
 def parse_otool_deployment_target(output: str) -> tuple[int, ...]:
     """Return the newest deployment target from one or more Mach-O slices."""
-    versions = [
-        parse_version(match.group(1))
-        for match in re.finditer(r"^\s*minos\s+(\d+(?:\.\d+)*)\s*$", output, re.MULTILINE)
-    ]
+    versions: list[tuple[int, ...]] = []
+    command: str | None = None
+    for line in output.splitlines():
+        stripped = line.strip()
+        if re.fullmatch(r"Load command \d+", stripped):
+            command = None
+        elif stripped == "cmd LC_BUILD_VERSION":
+            command = "build"
+        elif stripped == "cmd LC_VERSION_MIN_MACOSX":
+            command = "minimum"
+        elif command == "build" and (match := re.fullmatch(r"minos\s+(\d+(?:\.\d+)*)", stripped)):
+            versions.append(parse_version(match.group(1)))
+        elif command == "minimum" and (match := re.fullmatch(r"version\s+(\d+(?:\.\d+)*)", stripped)):
+            versions.append(parse_version(match.group(1)))
     if not versions:
-        raise ValueError("otool output contains no LC_BUILD_VERSION deployment target")
+        raise ValueError("otool output contains no macOS deployment target load command")
     return max(versions)
 
 
@@ -73,7 +87,7 @@ def ensure_compatible(
 
 
 def validate_deployment_targets(
-    executables: list[Path], platform_tag: str = MACOS_PLATFORM_TAG
+    executables: list[Path], platform_tag: str
 ) -> list[tuple[Path, tuple[int, ...]]]:
     """Validate every executable and return its measured deployment target."""
     measured = [(executable, deployment_target(executable)) for executable in executables]
@@ -84,11 +98,13 @@ def validate_deployment_targets(
 
 def main() -> None:
     parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("--platform", choices=tuple(MACOS_PLATFORMS), required=True)
     parser.add_argument("executables", type=Path, nargs="+")
     args = parser.parse_args()
-    for executable, version in validate_deployment_targets(args.executables):
+    platform_tag = MACOS_PLATFORMS[args.platform]
+    for executable, version in validate_deployment_targets(args.executables, platform_tag):
         rendered = ".".join(str(part) for part in version)
-        print(f"{executable}: macOS {rendered} <= {MACOS_PLATFORM_TAG}")
+        print(f"{executable}: macOS {rendered} <= {platform_tag}")
 
 
 if __name__ == "__main__":

+ 29 - 8
scripts/ci-workflow.spec.ts

@@ -370,7 +370,7 @@ describe('CI workflow', () => {
       name: 'python runtime / release-shaped matrix',
       uses: './.github/workflows/build-exe-for-python-sdk.yml',
       with: {
-        targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
+        targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64',
         ci: true,
       },
       secrets: {
@@ -462,7 +462,7 @@ describe('Python release workflows', () => {
     expect(build).toMatchObject({
       uses: './.github/workflows/build-exe-for-python-sdk.yml',
       with: {
-        targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
+        targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-macos-x64,node24-win-x64',
         release: true,
       },
     })
@@ -531,7 +531,7 @@ describe('Python release workflows', () => {
 
     const buildSteps: unknown[] = build.steps
     const manylinuxAddon = buildSteps.find(step => isRecord(step) && step.name === 'Rebuild Linux node-pty against manylinux 2.28')
-    const macosCheck = buildSteps.find(step => isRecord(step) && step.name === 'Check macOS deployment target')
+    const macosCheck = buildSteps.find(step => isRecord(step) && step.name === 'Check macOS payload architecture and deployment target')
     const manylinuxSmoke = buildSteps.find(step => isRecord(step) && step.name === 'Run wheel in a manylinux 2.28 container')
     const cleanVenvPosix = buildSteps.find(step => isRecord(step) && step.name === 'Install local SDK and runtime wheels into a clean venv (POSIX)')
     const cleanVenvWindows = buildSteps.find(step => isRecord(step) && step.name === 'Install local SDK and runtime wheels into a clean venv (Windows)')
@@ -541,7 +541,8 @@ describe('Python release workflows', () => {
     const realApiPreflightWindows = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test (Windows)')
     const installedRealApiPosix = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test (POSIX)')
     const installedRealApiWindows = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test (Windows)')
-    if (!isRecord(cleanVenvPosix) || !isRecord(cleanVenvWindows)
+    if (!isRecord(macosCheck) || typeof macosCheck.run !== 'string'
+      || !isRecord(cleanVenvPosix) || !isRecord(cleanVenvWindows)
       || !isRecord(installedKeylessPosix) || !isRecord(installedKeylessWindows)
       || !isRecord(realApiPreflightPosix) || !isRecord(realApiPreflightWindows)
       || !isRecord(installedRealApiPosix) || !isRecord(installedRealApiWindows)) {
@@ -564,6 +565,9 @@ describe('Python release workflows', () => {
     expect(JSON.stringify(plan.steps)).toContain('pep440_version')
     const workflowJson = JSON.stringify(workflow)
     expect(workflowJson).toContain('macosx_14_0_arm64')
+    expect(workflowJson).toContain('macosx_14_0_x86_64')
+    expect(workflowJson).toContain('node24-macos-x64')
+    expect(workflowJson).toContain('macos-15-intel')
     expect(workflowJson).toContain('win_amd64')
     expect(workflowJson).toContain('node24-win-x64')
     expect(workflowJson).toContain('windows-2025')
@@ -583,8 +587,10 @@ describe('Python release workflows', () => {
     expect(JSON.stringify(manylinuxAddon)).toContain('node-pty-glibc-versions.txt')
     expect(JSON.stringify(manylinuxAddon)).toContain('le 2.28')
     expect(macosCheck).toMatchObject({ if: "runner.os == 'macOS'" })
-    expect(JSON.stringify(macosCheck)).toContain('scripts/check-macos-deployment-target.py')
-    expect(JSON.stringify(macosCheck)).toContain('$EXE-spawn-helper')
+    expect(macosCheck.run).toContain('scripts/check-macos-deployment-target.py')
+    expect(macosCheck.run).toContain('lipo "$payload" -verify_arch')
+    expect(macosCheck.run).toContain('$EXE-rg')
+    expect(macosCheck.run).toContain('$EXE-spawn-helper')
     expect(JSON.stringify(installedKeylessPosix)).toContain('--scenario all')
     expect(JSON.stringify(installedKeylessPosix)).toContain('env -u PYTHONPATH')
     expect(JSON.stringify(installedKeylessWindows)).toContain('--scenario all --installed-wheel')
@@ -620,14 +626,29 @@ describe('Python release workflows', () => {
     }
     const runtimeScript: unknown[] = runtimeWheel.script
     const macosCheck = runtimeScript.find(
-      step => typeof step === 'string' && step.includes('PLATFORM" = macos-arm64'),
+      step => typeof step === 'string' && step.includes('${PLATFORM#macos-}'),
     )
     if (typeof macosCheck !== 'string') {
       throw new TypeError('GitLab CI must check the macOS deployment target')
     }
 
     expect(macosCheck).toContain('scripts/check-macos-deployment-target.py')
-    expect(macosCheck).toContain('"$EXE" "$EXE-spawn-helper"')
+    expect(macosCheck).toContain('lipo "$payload" -verify_arch')
+    expect(macosCheck).toContain('"$EXE" "$EXE-rg" "$EXE-spawn-helper"')
+  })
+
+  it('builds the macOS x64 wheel on the matching GitLab runner', () => {
+    const workflow = loadWorkflow('.gitlab-ci.yml')
+    const macosX64 = workflow['runtime-macos-x64']
+    const publish = workflow['publish-python']
+    if (!isRecord(macosX64) || !isRecord(publish) || !Array.isArray(publish.needs)) {
+      throw new TypeError('GitLab CI must define the macOS x64 runtime and publication jobs')
+    }
+
+    expect(macosX64.tags).toEqual(['macos-x64'])
+    expect(macosX64.variables).toMatchObject({ PKG_TARGET: 'node24-macos-x64', PLATFORM: 'macos-x64' })
+    expect(publish.needs).toContainEqual({ job: 'runtime-macos-x64', artifacts: true })
+    expect(JSON.stringify(publish.script)).toContain('macosx_14_0_x86_64.whl')
   })
 
   it('builds and black-box tests the Windows x64 wheel in GitLab', () => {

+ 4 - 3
scripts/verify-runtime-closure.spec.ts

@@ -21,6 +21,7 @@ const platforms = {
   'linux-x64': { tag: 'manylinux_2_28_x86_64', executable: 'runtime-linux-x64' },
   'linux-arm64': { tag: 'manylinux_2_28_aarch64', executable: 'runtime-linux-arm64' },
   'macos-arm64': { tag: 'macosx_14_0_arm64', executable: 'runtime-macos-arm64' },
+  'macos-x64': { tag: 'macosx_14_0_x86_64', executable: 'runtime-macos-x64' },
   'win-x64': { tag: 'win_amd64', executable: 'runtime-win-x64.exe' },
 }
 
@@ -64,7 +65,7 @@ describe('verifyRuntimeClosure', () => {
     expect(result.presetCount).toBe(1)
     expect(result.failures).toEqual([
       'standard preset -> @scope/linux (linux-arm64, linux-x64)',
-      'standard preset -> @scope/macos (macos-arm64)',
+      'standard preset -> @scope/macos (macos-arm64, macos-x64)',
       'standard preset -> @scope/windows (win-x64)',
     ])
   })
@@ -83,7 +84,7 @@ describe('verifyRuntimeClosure', () => {
     const result = await verifyRuntimeClosure(root)
 
     expect(result.failures).toEqual([
-      'standard preset -> @scope/conditional (linux-arm64, linux-x64, macos-arm64, win-x64)',
+      'standard preset -> @scope/conditional (linux-arm64, linux-x64, macos-arm64, macos-x64, win-x64)',
     ])
   })
 
@@ -117,7 +118,7 @@ describe('verifyRuntimeClosure', () => {
     const result = await verifyRuntimeClosure(root)
 
     expect(result.failures).toEqual([
-      'standard preset -> @scope/plugin [runtime dependency is "1.2.3"; expected workspace:] (linux-arm64, linux-x64, macos-arm64, win-x64)',
+      'standard preset -> @scope/plugin [runtime dependency is "1.2.3"; expected workspace:] (linux-arm64, linux-x64, macos-arm64, macos-x64, win-x64)',
     ])
   })
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff