feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
"""Locate and execute the bundled dsh CLI shipped with the Python SDK runtime.
|
2026-07-11 14:08:24 +08:00
|
|
|
|
|
|
|
|
Two runtime carriers coexist under ``runtime/``, both injected by the repo's
|
|
|
|
|
``scripts/build-exe-for-python-sdk.ts`` build (neither is checked into git):
|
|
|
|
|
|
2026-07-29 14:12:27 +08:00
|
|
|
- **exe (production)**: single-file Node executables named
|
feat(python-runtime): package the Windows x64 dsh executable
Add node24-win-x64 as the only supported Windows runtime target and publish it as a py3-none-win_amd64 wheel containing the conventional dsh and ripgrep .exe payload names. Keep Windows ARM64 rejected explicitly so Python cannot claim a carrier that CI and release automation do not build.
Teach the pkg builder to require a native x64 Windows host, validate both node-pty ConPTY addons, copy @vscode's win32 ripgrep executable, and recognize pkg's .exe output. Extend runtime resolution, wheel staging, payload validation, and the preset closure check so the Windows-specific PowerShell plugins and sidecars fail loud when omitted.
The sidecar resolver now maps a packaged main.exe to main-rg.exe; focused TypeScript and Python tests cover that name, the win_amd64 manifest, x64-only host selection, complete wheel payload, ConPTY inventory, and platform-conditioned plugin closure.
2026-08-23 15:39:18 +08:00
|
|
|
``deepseek-harness-sdk-runtime-<platform>-<arch>`` for Linux/macOS and an
|
|
|
|
|
``.exe`` counterpart for Windows. Each has a sibling ripgrep executable;
|
|
|
|
|
macOS also uses a sibling ``-spawn-helper``. The target machine needs no
|
|
|
|
|
Node installation.
|
2026-07-11 14:08:24 +08:00
|
|
|
- **node (dev-only)**: the full deploy closure under ``runtime/node/``
|
|
|
|
|
(``package.json`` + ``node_modules/``), executed as ``node
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js`` on a
|
2026-07-11 14:08:24 +08:00
|
|
|
system Node >= 22.19. It is the current checkout's source build, never
|
|
|
|
|
selected automatically, and excluded from wheel/sdist distributions.
|
|
|
|
|
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
Both carriers execute the same dsh command grammar. The Python SDK selects the
|
|
|
|
|
``sdk`` profile and requires an explicit Harness home; the installed ``dsh``
|
|
|
|
|
console command requires ``DSH_HOME`` for the same reason.
|
2026-07-11 14:08:24 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import platform
|
|
|
|
|
import shutil
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
PACKAGE_METADATA_FILENAME = "deepseek-harness-runtime.json"
|
|
|
|
|
|
|
|
|
|
RUNTIME_MODE_ENV_VAR = "DSH_RUNTIME_MODE"
|
|
|
|
|
|
feat(python-runtime): package the Windows x64 dsh executable
Add node24-win-x64 as the only supported Windows runtime target and publish it as a py3-none-win_amd64 wheel containing the conventional dsh and ripgrep .exe payload names. Keep Windows ARM64 rejected explicitly so Python cannot claim a carrier that CI and release automation do not build.
Teach the pkg builder to require a native x64 Windows host, validate both node-pty ConPTY addons, copy @vscode's win32 ripgrep executable, and recognize pkg's .exe output. Extend runtime resolution, wheel staging, payload validation, and the preset closure check so the Windows-specific PowerShell plugins and sidecars fail loud when omitted.
The sidecar resolver now maps a packaged main.exe to main-rg.exe; focused TypeScript and Python tests cover that name, the win_amd64 manifest, x64-only host selection, complete wheel payload, ConPTY inventory, and platform-conditioned plugin closure.
2026-08-23 15:39:18 +08:00
|
|
|
_PLATFORM_TAGS = {"linux": "linux", "darwin": "macos", "win32": "win"}
|
2026-07-11 14:08:24 +08:00
|
|
|
_ARCH_TAGS = {"x86_64": "x64", "amd64": "x64", "arm64": "arm64", "aarch64": "arm64"}
|
|
|
|
|
|
|
|
|
|
_EXE_ACQUISITION_HINT = (
|
|
|
|
|
"Two ways to get the executable: run `scripts/build-exe-for-python-sdk.ts` (via tsx) in a "
|
2026-07-13 17:02:56 +08:00
|
|
|
"deepseek-harness checkout, or install the matching `deepseek-harness-runtime-bin` platform "
|
|
|
|
|
"wheel retained by the `build-exe-for-python-sdk` CI workflow. For local development "
|
2026-07-11 14:08:24 +08:00
|
|
|
"against a repo source build, explicitly select the dev-only node carrier with "
|
|
|
|
|
f"{RUNTIME_MODE_ENV_VAR}=node (or resolve_bundled_launch_args('node'))."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bundled_package_dir() -> Path:
|
|
|
|
|
"""Root directory of the installed runtime package data (the directory of this module)."""
|
|
|
|
|
root = Path(__file__).resolve().parent
|
|
|
|
|
metadata = root / PACKAGE_METADATA_FILENAME
|
|
|
|
|
if not metadata.is_file():
|
|
|
|
|
raise FileNotFoundError(f"deepseek-harness-runtime-bin is missing {metadata}")
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bundled_runtime_path() -> Path:
|
|
|
|
|
"""Absolute path of the bundled single-file runtime executable for the current platform.
|
|
|
|
|
|
2026-07-29 23:20:08 +08:00
|
|
|
Raises FileNotFoundError when the platform is unsupported, the executable
|
2026-08-18 14:38:42 +08:00
|
|
|
has not been placed into this package, the required ripgrep sidecar is
|
|
|
|
|
missing, or the required macOS spawn helper is missing; the message names
|
|
|
|
|
the acquisition routes (acquisition strategy is deliberately separate from
|
|
|
|
|
this lookup interface, so an on-demand download can replace it without
|
|
|
|
|
touching callers).
|
2026-07-11 14:08:24 +08:00
|
|
|
"""
|
|
|
|
|
tag = _current_platform_tag()
|
feat(python-runtime): package the Windows x64 dsh executable
Add node24-win-x64 as the only supported Windows runtime target and publish it as a py3-none-win_amd64 wheel containing the conventional dsh and ripgrep .exe payload names. Keep Windows ARM64 rejected explicitly so Python cannot claim a carrier that CI and release automation do not build.
Teach the pkg builder to require a native x64 Windows host, validate both node-pty ConPTY addons, copy @vscode's win32 ripgrep executable, and recognize pkg's .exe output. Extend runtime resolution, wheel staging, payload validation, and the preset closure check so the Windows-specific PowerShell plugins and sidecars fail loud when omitted.
The sidecar resolver now maps a packaged main.exe to main-rg.exe; focused TypeScript and Python tests cover that name, the win_amd64 manifest, x64-only host selection, complete wheel payload, ConPTY inventory, and platform-conditioned plugin closure.
2026-08-23 15:39:18 +08:00
|
|
|
extension = ".exe" if tag.startswith("win-") else ""
|
|
|
|
|
path = bundled_package_dir() / "runtime" / f"deepseek-harness-sdk-runtime-{tag}{extension}"
|
2026-07-11 14:08:24 +08:00
|
|
|
if not path.is_file():
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
f"deepseek-harness-runtime-bin is missing the runtime executable at {path}. "
|
|
|
|
|
+ _EXE_ACQUISITION_HINT
|
|
|
|
|
)
|
feat(python-runtime): package the Windows x64 dsh executable
Add node24-win-x64 as the only supported Windows runtime target and publish it as a py3-none-win_amd64 wheel containing the conventional dsh and ripgrep .exe payload names. Keep Windows ARM64 rejected explicitly so Python cannot claim a carrier that CI and release automation do not build.
Teach the pkg builder to require a native x64 Windows host, validate both node-pty ConPTY addons, copy @vscode's win32 ripgrep executable, and recognize pkg's .exe output. Extend runtime resolution, wheel staging, payload validation, and the preset closure check so the Windows-specific PowerShell plugins and sidecars fail loud when omitted.
The sidecar resolver now maps a packaged main.exe to main-rg.exe; focused TypeScript and Python tests cover that name, the win_amd64 manifest, x64-only host selection, complete wheel payload, ConPTY inventory, and platform-conditioned plugin closure.
2026-08-23 15:39:18 +08:00
|
|
|
ripgrep = (
|
|
|
|
|
path.with_name(f"{path.stem}-rg.exe")
|
|
|
|
|
if tag.startswith("win-")
|
|
|
|
|
else Path(f"{path}-rg")
|
|
|
|
|
)
|
2026-08-14 13:06:21 +08:00
|
|
|
if not ripgrep.is_file():
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
f"deepseek-harness-runtime-bin is missing the ripgrep sidecar at {ripgrep}. "
|
|
|
|
|
+ _EXE_ACQUISITION_HINT
|
|
|
|
|
)
|
2026-07-29 23:20:08 +08:00
|
|
|
if tag.startswith("macos-"):
|
2026-07-30 01:29:18 +08:00
|
|
|
helper = Path(f"{path}-spawn-helper")
|
2026-07-29 23:20:08 +08:00
|
|
|
if not helper.is_file():
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
f"deepseek-harness-runtime-bin is missing the node-pty spawn helper at {helper}. "
|
|
|
|
|
+ _EXE_ACQUISITION_HINT
|
|
|
|
|
)
|
2026-07-11 14:08:24 +08:00
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def resolve_bundled_launch_args(mode: str | None = None) -> tuple[str, ...]:
|
|
|
|
|
"""The argv tuple that launches the bundled runtime.
|
|
|
|
|
|
|
|
|
|
Mode selection: the explicit ``mode`` argument wins, then the
|
|
|
|
|
``DSH_RUNTIME_MODE`` environment variable (``exe`` | ``node``), then
|
|
|
|
|
automatic resolution. Automatic resolution finds the production exe ONLY —
|
|
|
|
|
the dev-only node carrier must be selected explicitly so a production
|
|
|
|
|
deployment can never silently ride on a source build. Returns
|
|
|
|
|
``(exe_path,)`` in exe mode and ``(node_path, bin_js_path)`` in node mode;
|
|
|
|
|
raises FileNotFoundError when the selected carrier is unavailable and
|
|
|
|
|
ValueError for an unknown mode value.
|
|
|
|
|
"""
|
|
|
|
|
selected = mode if mode is not None else os.environ.get(RUNTIME_MODE_ENV_VAR)
|
|
|
|
|
if selected is None or selected == "exe":
|
|
|
|
|
return (str(bundled_runtime_path()),)
|
|
|
|
|
if selected == "node":
|
|
|
|
|
return _node_launch_args()
|
|
|
|
|
raise ValueError(
|
|
|
|
|
f"unsupported DeepSeek Harness runtime mode {selected!r}: expected 'exe' or 'node' "
|
|
|
|
|
f"(explicit argument or ${RUNTIME_MODE_ENV_VAR})"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _current_platform_tag() -> str:
|
|
|
|
|
plat = _PLATFORM_TAGS.get(sys.platform)
|
|
|
|
|
arch = _ARCH_TAGS.get(platform.machine().lower())
|
2026-08-23 19:18:59 +08:00
|
|
|
if (
|
|
|
|
|
plat is None
|
|
|
|
|
or arch is None
|
|
|
|
|
or (plat == "win" and arch != "x64")
|
|
|
|
|
or (plat == "macos" and arch != "arm64")
|
|
|
|
|
):
|
2026-07-11 14:08:24 +08:00
|
|
|
raise FileNotFoundError(
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
"no bundled DeepSeek Harness SDK runtime exists for this platform "
|
2026-07-11 14:08:24 +08:00
|
|
|
f"(sys.platform={sys.platform!r}, machine={platform.machine()!r}); supported: "
|
feat(python-runtime): package the Windows x64 dsh executable
Add node24-win-x64 as the only supported Windows runtime target and publish it as a py3-none-win_amd64 wheel containing the conventional dsh and ripgrep .exe payload names. Keep Windows ARM64 rejected explicitly so Python cannot claim a carrier that CI and release automation do not build.
Teach the pkg builder to require a native x64 Windows host, validate both node-pty ConPTY addons, copy @vscode's win32 ripgrep executable, and recognize pkg's .exe output. Extend runtime resolution, wheel staging, payload validation, and the preset closure check so the Windows-specific PowerShell plugins and sidecars fail loud when omitted.
The sidecar resolver now maps a packaged main.exe to main-rg.exe; focused TypeScript and Python tests cover that name, the win_amd64 manifest, x64-only host selection, complete wheel payload, ConPTY inventory, and platform-conditioned plugin closure.
2026-08-23 15:39:18 +08:00
|
|
|
"Linux x64/arm64, macOS arm64, and Windows x64. " + _EXE_ACQUISITION_HINT
|
2026-07-11 14:08:24 +08:00
|
|
|
)
|
|
|
|
|
return f"{plat}-{arch}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _node_launch_args() -> tuple[str, str]:
|
|
|
|
|
node_root = bundled_package_dir() / "runtime" / "node"
|
|
|
|
|
bin_js = (
|
2026-08-10 21:39:47 +08:00
|
|
|
node_root
|
|
|
|
|
/ "node_modules"
|
|
|
|
|
/ "@deepseek-ai"
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
/ "dsh"
|
2026-08-10 21:39:47 +08:00
|
|
|
/ "lib"
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
/ "bin.js"
|
2026-07-11 14:08:24 +08:00
|
|
|
)
|
|
|
|
|
if not bin_js.is_file():
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
f"the dev-only node runtime closure is missing at {node_root} "
|
|
|
|
|
f"(no {bin_js}); run `scripts/build-exe-for-python-sdk.ts` in a deepseek-harness "
|
|
|
|
|
"checkout, which builds and copies the deploy closure here. The node carrier "
|
|
|
|
|
"is for repo-local development only — production uses the single-file exe."
|
|
|
|
|
)
|
|
|
|
|
node = shutil.which("node")
|
|
|
|
|
if node is None:
|
|
|
|
|
raise FileNotFoundError(
|
|
|
|
|
"the node runtime mode needs a system `node` (>=22.19) on PATH; "
|
|
|
|
|
"install Node.js or use the exe mode"
|
|
|
|
|
)
|
|
|
|
|
return (node, str(bin_js))
|
|
|
|
|
|
|
|
|
|
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
def main() -> None:
|
|
|
|
|
"""Execute the bundled dsh CLI with an explicitly selected Harness home."""
|
|
|
|
|
if not os.environ.get("DSH_HOME", "").strip():
|
|
|
|
|
print(
|
|
|
|
|
"dsh: the Python runtime command requires an explicit DSH_HOME; "
|
|
|
|
|
"it never uses ~/.dsh implicitly",
|
|
|
|
|
file=sys.stderr,
|
|
|
|
|
)
|
|
|
|
|
raise SystemExit(2)
|
|
|
|
|
argv = (*resolve_bundled_launch_args(), *sys.argv[1:])
|
|
|
|
|
os.execvpe(argv[0], argv, os.environ)
|
|
|
|
|
|
|
|
|
|
|
2026-07-11 14:08:24 +08:00
|
|
|
__all__ = [
|
|
|
|
|
"PACKAGE_METADATA_FILENAME",
|
|
|
|
|
"RUNTIME_MODE_ENV_VAR",
|
|
|
|
|
"bundled_package_dir",
|
|
|
|
|
"bundled_runtime_path",
|
feat(python-runtime): package the dsh CLI and profile assets
Make the zero-code dsh-python-runtime-closure depend on the real @deepseek-ai/dsh application and every required profile peer, then package apps/cli's built bin instead of the deleted Python carrier. Rename executables to deepseek-harness-sdk-runtime-<platform>-<arch>, update wheel/platform/build workflow discovery, and install a Python dsh console command that requires explicit DSH_HOME before exec.
Include profile, bundle, preset, native addon, and shared-library assets needed by the full CLI. Remove the checked-in default cordis.yml and preserve the existing wheel distribution names, Python module names, sidecar validation, and wire identity. Runtime resolution and release tests pin the new artifacts and dev Node carrier.
2026-08-23 14:56:02 +08:00
|
|
|
"main",
|
2026-07-11 14:08:24 +08:00
|
|
|
"resolve_bundled_launch_args",
|
|
|
|
|
]
|