From defb9c373612682ef4a7f2ac7cf71a52e60bf526 Mon Sep 17 00:00:00 2001 From: fz Date: Fri, 18 Sep 2026 17:44:15 +0800 Subject: [PATCH] fix(sdk): shorten bundled Python resource paths on Windows --- ...2026-09-17-shared-office-runtime.i18n.yaml | 4 +-- .../2026-09-17-shared-office-runtime.md | 2 +- .../2026-09-17-shared-office-runtime.zh.md | 2 +- .gitignore | 3 +-- python/sdk-runtime/README.i18n.yaml | 4 +-- python/sdk-runtime/README.md | 2 +- python/sdk-runtime/README.zh.md | 2 +- python/sdk-runtime/hatch_build.py | 4 +-- python/sdk-runtime/pyproject.toml | 8 +++++- python/sdk-runtime/runtime-bootstrap.mjs | 4 ++- .../src/deepseek_harness_runtime/__init__.py | 2 +- python/sdk/tests/test_release_version.py | 15 ++++++++++- python/sdk/tests/test_runtime_resolution.py | 4 +-- scripts/build-exe-for-python-sdk.spec.ts | 2 +- scripts/build-exe-for-python-sdk.ts | 2 +- scripts/build-python-release.py | 27 ++++++++++--------- scripts/smoke-python-runtime.py | 5 ++-- scripts/translation-pairing.spec.ts | 3 +++ scripts/translation-pairing.ts | 6 ++--- 19 files changed, 63 insertions(+), 38 deletions(-) diff --git a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.i18n.yaml b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.i18n.yaml index 068b3c89c4..f3e123135e 100644 --- a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.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-09-17-shared-office-runtime.md -2026-09-17-shared-office-runtime.md: b8aca3e84c6b426f19d5db4149afef0592c73db7 -2026-09-17-shared-office-runtime.zh.md: 792f4c8bc2dce532e57916c9e95d182161f99c16 +2026-09-17-shared-office-runtime.md: 25b6ddccbb5b17b93bec2c0b024dfcb63e94abc3 +2026-09-17-shared-office-runtime.zh.md: 99dffe8d0233e60480689ff983b6261cbb83bb7b diff --git a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.md b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.md index b8aca3e84c..25b6ddccbb 100644 --- a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.md +++ b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.md @@ -18,7 +18,7 @@ The [Desktop primary-runtime decision](../feature/2026-09-14-desktop-primary-run `runtime.json` stores Python, Node.js and pnpm versions at the top level and all Python distribution versions in `pythonPackages`. Build metadata does not single out numpy or pandas. The shared parser accepts legacy `components` files without rewriting them, retains their consistency checks, and returns only the canonical flat fields. Mixed formats are rejected. The build digest includes the assembly format so changed manifest bytes invalidate payload reuse. -The Python runtime wheel carries target-native CPython and Office libraries plus external skills in a sibling resource directory. Bundling supplies defaults; the skill registry still lets project, custom and user skills override same-name bundled entries, and profile patches can disable or replace Office skills without replacing Python. This retains configurable workflows while eliminating a separate environment installation step. Real filesystem resources let Python load native extensions and skills invoke their shared checker without startup extraction. The wheel grows by the compressed payload size; public-index size limits remain enforced by the release workflow. +The Python runtime wheel carries target-native CPython and Office libraries plus external skills in a sibling `-/` resource directory. Short platform directory names leave room for Python extension and dependency DLL paths after installation on Windows. Bundling supplies defaults; the skill registry still lets project, custom and user skills override same-name bundled entries, and profile patches can disable or replace Office skills without replacing Python. This retains configurable workflows while eliminating a separate environment installation step. Real filesystem resources let Python load native extensions and skills invoke their shared checker without startup extraction. The wheel grows by the compressed payload size; public-index size limits remain enforced by the release workflow. ## Alternatives considered diff --git a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.zh.md b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.zh.md index 792f4c8bc2..99dffe8d02 100644 --- a/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.zh.md +++ b/.agents/notes/implemented/architecture/2026-09-17-shared-office-runtime.zh.md @@ -18,7 +18,7 @@ SDK 部署需要与 Desktop 相同的 Office 创作库,同时将解释器 payl `runtime.json` 在顶层保存 Python、Node.js 和 pnpm 版本,并在 `pythonPackages` 中保存全部 Python 分发包版本。构建元数据不单独列出 numpy 或 pandas。共享解析器接受旧 `components` 文件而不改写它们,保留旧格式的一致性校验,并仅返回统一的扁平字段。混合格式会被拒绝。构建摘要包含组装格式,因此清单字节变化会使旧产物身份失效。 -Python runtime wheel 将目标平台的 CPython、Office 库和外部 skills 放在可执行文件同级的资源目录中。打包提供默认资源;skill 注册表仍允许项目、自定义目录和用户 skills 覆盖同名随包条目,profile patch 可在保留 Python 的同时禁用或替换 Office skills。这样既保留工作流配置能力,又省去单独安装环境的步骤。真实文件系统资源允许 Python 加载原生扩展,并让 skills 调用共用检查脚本,无需启动时解包。wheel 体积增加一个压缩 payload;发布流程仍执行公开索引的大小限制检查。 +Python runtime wheel 将目标平台的 CPython、Office 库和外部 skills 放在可执行文件同级的 `-/` 资源目录中。较短的平台目录名为 Windows 安装后的 Python 扩展与依赖 DLL 路径保留长度空间。打包提供默认资源;skill 注册表仍允许项目、自定义目录和用户 skills 覆盖同名随包条目,profile patch 可在保留 Python 的同时禁用或替换 Office skills。这样既保留工作流配置能力,又省去单独安装环境的步骤。真实文件系统资源允许 Python 加载原生扩展,并让 skills 调用共用检查脚本,无需启动时解包。wheel 体积增加一个压缩 payload;发布流程仍执行公开索引的大小限制检查。 ## 考虑过的替代方案 diff --git a/.gitignore b/.gitignore index 7ad33230ad..86e330fc0c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,7 @@ mise.toml dist-exe/ /dist/ apps/desktop/.desktop-build/ -python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-* -python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/ +python/sdk-runtime/src/deepseek_harness_runtime/runtime/ python/**/__pycache__/ python/**/.pytest_cache/ packages/**/__pycache__/ diff --git a/python/sdk-runtime/README.i18n.yaml b/python/sdk-runtime/README.i18n.yaml index b1dc01568b..c880a126ec 100644 --- a/python/sdk-runtime/README.i18n.yaml +++ b/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: a767bcea00a5bb116fdf25a4d1d8fd916f94c5f5 -README.zh.md: 539fae9f4f71df394bde54814b5190ea73126474 +README.md: 202af65986ae2c78aeb092f0b4adb88cd1c97e9b +README.zh.md: 12ff0dbac184f67f8e821b6fbb9e22748563babb diff --git a/python/sdk-runtime/README.md b/python/sdk-runtime/README.md index a767bcea00..202af65986 100644 --- a/python/sdk-runtime/README.md +++ b/python/sdk-runtime/README.md @@ -12,7 +12,7 @@ Production executables are named `deepseek-harness-sdk-runtime-- Each target also requires `-office/`, where the stem excludes `.exe`. This directory contains the complete installed Office packages and their dependencies, preserving engine resources, manifests, licenses, source inventories, and helper permissions. Copy this directory together with the executable. A missing target engine fails the sidecar build with its npm package name and target platform/architecture. -Each wheel also includes `-resources/primary-runtime/` (CPython and the locked Office Python libraries) and sibling `office-skills/` (three default workflows and their shared checker). These are ordinary relocatable files, not bytes embedded in the executable. The shared builder selects target-native archives for all five wheel targets and executes its smoke on the native build host. Packaging and installed-runtime lookup reject missing resources, wrong-platform metadata, and lost Python executable permissions. +Each wheel also includes `-/primary-runtime/` (CPython and the locked Office Python libraries) and sibling `office-skills/` (three default workflows and their shared checker). These are ordinary relocatable files, not bytes embedded in the executable. The shared builder selects target-native archives for all five wheel targets and executes its smoke on the native build host. Packaging and installed-runtime lookup reject missing resources, wrong-platform metadata, and lost Python executable permissions. The short platform directory avoids repeating the executable name in Python DLL paths on Windows. The packaged bootstrap supplies `DSH_BUNDLED_PRIMARY_RUNTIME` as a carrier default. The `sdk` profile uses it when `DSH_PRIMARY_RUNTIME` is unset; an explicit path overrides it, and an empty string disables the query and Office provider. External payloads retain the `primary-runtime/` plus sibling `office-skills/` layout. The SDK reads Python in place without copying it into `DSH_HOME`. Source and dev-only Node carriers have no bundled default; they use an explicit `DSH_PRIMARY_RUNTIME`. diff --git a/python/sdk-runtime/README.zh.md b/python/sdk-runtime/README.zh.md index 539fae9f4f..12ff0dbac1 100644 --- a/python/sdk-runtime/README.zh.md +++ b/python/sdk-runtime/README.zh.md @@ -12,7 +12,7 @@ wheel 包会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python 每个目标还要求 `-office/`,其中 stem 不含 `.exe`。该目录包含完整的已安装 Office 包及其依赖,保留引擎资源、清单、许可证、源码清单与辅助程序权限。复制可执行文件时必须一并复制此目录。缺少目标引擎会使 sidecar 构建失败,错误会指出其 npm 包名与目标平台/架构。 -每个 wheel 还包含 `-resources/primary-runtime/`(CPython 与锁定版本的 Office Python 库)及同级 `office-skills/`(三个默认工作流与共用检查脚本)。它们是可重定位的普通文件,不嵌入可执行文件。共享构建器为全部五个 wheel 目标选择原生归档,并在对应构建主机上执行冒烟检查。打包与已安装运行时定位会拒绝缺失资源、平台不符的元数据及 Python 执行权限丢失。 +每个 wheel 还包含 `-/primary-runtime/`(CPython 与锁定版本的 Office Python 库)及同级 `office-skills/`(三个默认工作流与共用检查脚本)。它们是可重定位的普通文件,不嵌入可执行文件。共享构建器为全部五个 wheel 目标选择原生归档,并在对应构建主机上执行冒烟检查。打包与已安装运行时定位会拒绝缺失资源、平台不符的元数据及 Python 执行权限丢失。 较短的平台目录避免在 Windows Python DLL 路径中重复可执行文件名称。 打包启动器通过 `DSH_BUNDLED_PRIMARY_RUNTIME` 提供载体默认路径。`sdk` profile 在未设置 `DSH_PRIMARY_RUNTIME` 时使用该路径;显式路径覆盖它,空字符串禁用查询与 Office 提供方。外部 payload 保持 `primary-runtime/` 与同级 `office-skills/` 布局。SDK 原位读取 Python,不复制到 `DSH_HOME`。源码与仅供开发的 Node 载体没有随包默认路径,需显式设置 `DSH_PRIMARY_RUNTIME`。 diff --git a/python/sdk-runtime/hatch_build.py b/python/sdk-runtime/hatch_build.py index 1f249ae718..f1357bff52 100644 --- a/python/sdk-runtime/hatch_build.py +++ b/python/sdk-runtime/hatch_build.py @@ -77,7 +77,7 @@ class RuntimeBuildHook(BuildHookInterface): target = next(name for name, value in _PLATFORMS.items() if value[0] == platform_tag) runtime_dir = Path(self.root) / "src" / "deepseek_harness_runtime" / "runtime" runtime_files = sorted( - runtime_dir.glob("deepseek-harness-sdk-runtime-*") if runtime_dir.is_dir() else [] + (path for path in runtime_dir.iterdir() if path.name != "node") if runtime_dir.is_dir() else [] ) expected_files = ( [expected_executable, f"{expected_executable.removesuffix('.exe')}-rg.exe"] @@ -88,7 +88,7 @@ class RuntimeBuildHook(BuildHookInterface): expected_files.append(f"{expected_executable}-spawn-helper") office = runtime_dir / f"{expected_executable.removesuffix('.exe')}-office" expected_files.append(office.name) - resources = runtime_dir / f"{expected_executable.removesuffix('.exe')}-resources" + resources = runtime_dir / target expected_files.append(resources.name) expected_files.sort() found_files = [path.name for path in runtime_files] diff --git a/python/sdk-runtime/pyproject.toml b/python/sdk-runtime/pyproject.toml index 4e1c58fd2d..80c49db937 100644 --- a/python/sdk-runtime/pyproject.toml +++ b/python/sdk-runtime/pyproject.toml @@ -22,7 +22,13 @@ dsh = "deepseek_harness_runtime:main" # Include the injected dsh executable and sidecars; exclude the dev-only node closure. [tool.hatch.build] -artifacts = ["src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*", "src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**"] +artifacts = [ + "src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*", + "src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**", + "src/deepseek_harness_runtime/runtime/linux-*/**", + "src/deepseek_harness_runtime/runtime/macos-*/**", + "src/deepseek_harness_runtime/runtime/win-*/**", +] exclude = ["src/deepseek_harness_runtime/runtime/node"] [tool.hatch.build.targets.wheel] diff --git a/python/sdk-runtime/runtime-bootstrap.mjs b/python/sdk-runtime/runtime-bootstrap.mjs index 2d9bc39450..52836d746e 100644 --- a/python/sdk-runtime/runtime-bootstrap.mjs +++ b/python/sdk-runtime/runtime-bootstrap.mjs @@ -1,6 +1,7 @@ #!/usr/bin/env node /** Private entry owned by the Python single-file runtime packaging. */ import { registerHooks } from 'node:module' +import { dirname, join } from 'node:path' import { isSea } from 'node:sea' import { fileURLToPath, pathToFileURL } from 'node:url' @@ -30,7 +31,8 @@ if (aclRunner !== undefined && process.argv[2] === aclRunner) { } else if (selection === undefined) { if (isSea()) { // Carrier default stays separate so process/home environment and profile patches can override it. - process.env.DSH_BUNDLED_PRIMARY_RUNTIME = `${process.execPath.replace(/\.exe$/i, '')}-resources/primary-runtime` + const platform = process.platform === 'darwin' ? 'macos' : process.platform === 'win32' ? 'win' : process.platform + process.env.DSH_BUNDLED_PRIMARY_RUNTIME = join(dirname(process.execPath), `${platform}-${process.arch}`, 'primary-runtime') } const { runCli } = await import('@deepseek-ai/dsh/lib/bin.js') await runCli() diff --git a/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py b/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py index b84eefa412..174d629160 100644 --- a/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py +++ b/python/sdk-runtime/src/deepseek_harness_runtime/__init__.py @@ -107,7 +107,7 @@ def bundled_runtime_path() -> Path: f"deepseek-harness-runtime-bin is missing the Office sidecar engine {engine} at {office}. " + _EXE_ACQUISITION_HINT ) - validate_resources(path.with_name(f"{path.name.removesuffix('.exe')}-resources"), tag) + validate_resources(path.with_name(tag), tag) return path diff --git a/python/sdk/tests/test_release_version.py b/python/sdk/tests/test_release_version.py index 1e39e02317..b6ddb572e3 100644 --- a/python/sdk/tests/test_release_version.py +++ b/python/sdk/tests/test_release_version.py @@ -108,6 +108,19 @@ def test_stage_sdk_keeps_distribution_module_and_runtime_pin_distinct(tmp_path: assert (destination / "src" / "deepseek_harness" / "__init__.py").is_file() +def test_copy_package_omits_generated_carriers_before_staging_one_target(tmp_path: Path) -> None: + source = tmp_path / "source" + module = source / "src/deepseek_harness_runtime" + for path in ("runtime/macos-arm64/primary-runtime/runtime.json", "runtime/node/package.json", + "runtime/deepseek-harness-sdk-runtime-win-x64.exe", "__init__.py", "_resources.py"): + file = module / path + file.parent.mkdir(parents=True, exist_ok=True) + file.touch() + destination = tmp_path / "staged" + build_python_release.copy_package(source, destination) + assert sorted(path.name for path in (destination / "src/deepseek_harness_runtime").iterdir()) == ["__init__.py", "_resources.py"] + + @pytest.mark.parametrize( ("target", "with_helper"), [("linux-x64", False), ("macos-arm64", True), ("macos-x64", True), ("win-x64.exe", False)], @@ -136,7 +149,7 @@ def test_stage_runtime_copies_platform_payload( office_asset = office / "node_modules" / "@deepseek-ai" / "libreoffice-kit-wasm" / "assets" / "soffice.data" office_asset.parent.mkdir(parents=True) office_asset.write_bytes(b"office data") - resources = executable.with_name(f"{executable.name.removesuffix('.exe')}-resources") + resources = executable.with_name(executable.name.removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe")) resource = resources / "office-skills/scripts/check_office.py" resource.parent.mkdir(parents=True) resource.write_text("checker") diff --git a/python/sdk/tests/test_runtime_resolution.py b/python/sdk/tests/test_runtime_resolution.py index 0fdc2dd663..ecab8a3159 100644 --- a/python/sdk/tests/test_runtime_resolution.py +++ b/python/sdk/tests/test_runtime_resolution.py @@ -35,7 +35,7 @@ def _resource_sidecars(executable: Path, native_targets: tuple[str, ...] = ("dar adapter.write_text(json.dumps({"optionalDependencies": { f"@deepseek-ai/libreoffice-kit-{target}": "0.0.1" for target in (*native_targets, "wasm") }}), encoding="utf-8") - resources = executable.with_name(f"{executable.name.removesuffix('.exe')}-resources") + resources = executable.with_name(tag) manifest = resources / "primary-runtime/runtime.json" manifest.parent.mkdir(parents=True) manifest.write_text(json.dumps({"platform": native.rsplit("-", 1)[0], "arch": tag.rsplit("-", 1)[1], @@ -63,7 +63,7 @@ def test_unknown_explicit_mode_fails_loud() -> None: def test_authoring_resources_validate_installed_and_wheel_payloads(tmp_path: Path, target: str, invalid: str | None) -> None: executable = tmp_path / f"deepseek-harness-sdk-runtime-{target}" _resource_sidecars(executable) - root = Path(f"{executable}-resources") + root = tmp_path / target python = root / "primary-runtime/dependencies/python" / ("python.exe" if target == "win-x64" else "bin/python3") if invalid == "mode" and target == "win-x64": pytest.skip("Windows executables do not require a POSIX executable bit") diff --git a/scripts/build-exe-for-python-sdk.spec.ts b/scripts/build-exe-for-python-sdk.spec.ts index ff84e89ec9..f2f563fd61 100644 --- a/scripts/build-exe-for-python-sdk.spec.ts +++ b/scripts/build-exe-for-python-sdk.spec.ts @@ -102,7 +102,7 @@ describe('Python runtime executable builder CLI', () => { expect(result.stdout).toContain('exec pkg') expect(result.stdout).toContain('--sea --targets node24-macos-x64') expect(result.stdout).toContain('prepare Python and Office skills for mac-x64') - expect(result.stdout).toContain('deepseek-harness-sdk-runtime-macos-x64-resources') + expect(result.stdout).toContain(join(root, 'dist-exe', 'macos-x64')) }) it('rejects a Windows arm64 product before any build step', () => { diff --git a/scripts/build-exe-for-python-sdk.ts b/scripts/build-exe-for-python-sdk.ts index eb7e7dc213..341bf95a35 100644 --- a/scripts/build-exe-for-python-sdk.ts +++ b/scripts/build-exe-for-python-sdk.ts @@ -450,7 +450,7 @@ class SingleExeBuild { console.log(`build-exe-for-python-sdk: copied ${packages.length} Office packages to ${office}`) } const ripgrep = await this.copyRipgrepSidecar(target, product) - const resources = `${productBase}-resources` + const resources = join(this.outDir, `${target.platform}-${target.arch}`) const runtimeTarget = `${target.platform === 'macos' ? 'mac' : target.platform}-${target.arch}` as PrimaryRuntimeTarget if (this.cli.dryRun) { console.log(`build-exe-for-python-sdk: [dry-run] prepare Python and Office skills for ${runtimeTarget} in ${resources}`) diff --git a/scripts/build-python-release.py b/scripts/build-python-release.py index 1e26874b29..2918feb380 100644 --- a/scripts/build-python-release.py +++ b/scripts/build-python-release.py @@ -149,18 +149,21 @@ def validate_release_tag(tag: str | None, version: str) -> None: def copy_package(source: Path, destination: Path) -> None: + generated_parent = source / "src" / "deepseek_harness_runtime" + ignore_files = shutil.ignore_patterns( + ".venv", ".pytest_cache", "__pycache__", "*.pyc", "dist", "node_modules", + ) + + def ignore(directory: str, names: list[str]) -> set[str]: + ignored = ignore_files(directory, names) + if Path(directory) == generated_parent: + ignored.add("runtime") + return ignored + shutil.copytree( source, destination, - ignore=shutil.ignore_patterns( - ".venv", - ".pytest_cache", - "__pycache__", - "*.pyc", - "dist", - "node_modules", - "deepseek-harness-sdk-runtime-*", - ), + ignore=ignore, ) @@ -228,7 +231,7 @@ def stage_runtime(destination: Path, version: str, executable: Path, executable_ shutil.copy2(source_directory / filename, runtime_dir / filename) office = office_sidecar_name(executable_name) shutil.copytree(source_directory / office, runtime_dir / office) - resources = f"{executable_name.removesuffix('.exe')}-resources" + resources = executable_name.removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe") shutil.copytree(source_directory / resources, runtime_dir / resources) @@ -301,12 +304,12 @@ def verify_wheel( f"{wheel} has license files {license_files}, expected {expected_license_files}" ) runtime_payload = [ - name for name in archive.namelist() if "/runtime/deepseek-harness-sdk-runtime-" in name + name for name in archive.namelist() if name.startswith("deepseek_harness_runtime/runtime/") ] if package == "runtime": assert platform is not None office = office_sidecar_name(platform[1]) - resources = f"{platform[1].removesuffix('.exe')}-resources" + resources = platform[1].removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe") expected_files = sorted((*runtime_filenames(platform[1]), office, resources)) found_files = sorted({name.split("/runtime/", 1)[1].split("/", 1)[0] for name in runtime_payload}) if found_files != expected_files: diff --git a/scripts/smoke-python-runtime.py b/scripts/smoke-python-runtime.py index 052eef696d..264757bf8b 100644 --- a/scripts/smoke-python-runtime.py +++ b/scripts/smoke-python-runtime.py @@ -808,7 +808,7 @@ def smoke_sdk_authoring(base_url: str, executable: Path, update_snapshots: bool) """Query the bundled Python and switch skills without replacing that environment.""" from deepseek_harness import DeepSeekHarness - resources = executable.with_name(f"{executable.name.removesuffix('.exe')}-resources") + resources = executable.with_name(executable.name.removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe")) manifest = json.loads((resources / "primary-runtime/runtime.json").read_text()) for mode in ("default", "replacement", "disabled"): with tempfile.TemporaryDirectory(prefix="dsh-sdk-authoring-") as temporary: @@ -871,7 +871,8 @@ def smoke_sdk_office(executable: Path) -> None: root = Path(temporary).resolve() relocated = root / executable.name stem = executable.name.removesuffix(".exe") - for source in executable.parent.glob(f"{stem}*"): + resources = executable.with_name(stem.removeprefix("deepseek-harness-sdk-runtime-")) + for source in [*executable.parent.glob(f"{stem}*"), resources]: destination = root / source.name if source.is_dir(): shutil.copytree(source, destination) diff --git a/scripts/translation-pairing.spec.ts b/scripts/translation-pairing.spec.ts index 54e2fabc81..1c902d3520 100644 --- a/scripts/translation-pairing.spec.ts +++ b/scripts/translation-pairing.spec.ts @@ -319,6 +319,8 @@ describe('translation scope discovery', () => { '.agents/notes/proposed/feature.md', 'docs/guide.md', 'python/guide.md', + 'python/sdk-runtime/README.md', + 'python/sdk-runtime/src/deepseek_harness_runtime/README.md', ])('includes %s', (file) => { expect(isTranslationScopeFile(file)).toBe(true) }) @@ -336,6 +338,7 @@ describe('translation scope discovery', () => { 'coverage/report/README.md', 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-macos-arm64/README.md', 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/README.md', + 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/macos-arm64/office-skills/office-docx/SKILL.md', ])('excludes non-source or non-README path %s', (file) => { expect(isTranslationScopeFile(file)).toBe(false) }) diff --git a/scripts/translation-pairing.ts b/scripts/translation-pairing.ts index e4c0919a2f..917b912c23 100644 --- a/scripts/translation-pairing.ts +++ b/scripts/translation-pairing.ts @@ -165,8 +165,7 @@ export const TRANSLATION_SCOPE_GLOB_EXCLUDES = [ '**/.pytest_cache/**', 'apps/web/dist/**', '.artifacts/**', - 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**', - 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/**', + 'python/sdk-runtime/src/deepseek_harness_runtime/runtime/**', 'vendor/**', ] @@ -177,8 +176,7 @@ function isTranslationSourceExcluded(file: string): boolean { || segment.startsWith('.doc-typecheck-') || segment.startsWith('.node-next-types-')) || file.startsWith('apps/web/dist/') - || file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-') - || file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/') + || file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/') } /** Whether one discovered Markdown or sidecar path belongs to the bilingual source corpus. */