feat(document): decouple shared Office conversion from preview

This commit is contained in:
yudshj committed 2026-09-17 11:15:21 +08:00
1 parent e7a4621aa9
commit 9d2a3bf2b7
109 files changed
+3617 -70

No files matched your search

+2 -2
View File
@@ -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: 8ab226427f89d2746d6da13bcd8bd254731f2460
README.zh.md: 23a042006c38425a83347322fa63f0fafb319d0d
README.md: ba1814ce00dea9dd35bcfbb330801942b86af155
README.zh.md: 792c7e06a29be987a25887882b6df976138b194f
+5 -1
View File
@@ -10,6 +10,8 @@ The wheel installs a `dsh` console command and the `deepseek_harness_runtime` Py
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.
Each target also requires `<executable-stem>-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.
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.
Both carriers execute the same `dsh` grammar and shipped profiles, including the standalone `sdk-minimal` tree and the full `web` profile with its frontend assets. The private `dsh-python-runtime-closure` manifest defines the packaged dependency closure; there is no Python-specific Node application or checked-in default `cordis.yml`.
@@ -27,6 +29,8 @@ Unsupported platforms and missing executables or sidecars raise `FileNotFoundErr
`dsh` initializes shipped profiles under the explicit home, composes their bundle patches, and loads bundled plugins from the executable's virtual filesystem. Because operating-system symlinks cannot enter that filesystem, packaged launches maintain small real ESM proxy packages under `$DSH_HOME/profiles/node_modules`. Each proxy mirrors explicit runtime exports, records the original package identity, and re-exports the virtual module URL. Built-in rows and external plugin peers therefore share one Cordis/module instance. Native shared libraries and Windows ConPTY addons are packaged with native addons, while ripgrep and the macOS PTY helper remain executable sidecars.
The Python bootstrap resolves the Office kit from its adjacent directory so native helpers and URL Workers use real filesystem paths. The kit owns engine selection and validation; the Python bootstrap adds no runtime download or compilation.
External profile management uses `dsh plugin --profile <name> ...`. That command requires `pnpm` on `PATH`; ordinary SDK/profile execution does not.
## Build and distribution
@@ -35,4 +39,4 @@ Production deployment permits unused workspace patches for packages outside the
From the repository root, `pnpm exec tsx scripts/build-exe-for-python-sdk.ts` verifies the closure, builds packages, deploys a symlink-free tree, packages the selected target, and syncs the executable and sidecars into this module. `scripts/build-python-release.py` stages release-shaped wheels at the root repository version and pins `deepseek-harness-sdk` to the exact runtime version.
The installed-wheel smoke creates a clean virtual environment outside the checkout, proves the installed distribution and executable identities, then exercises default and customized SDK profiles, external plugins, MCP, native tools, direct JSON-RPC, committed snapshots, and the real provider on trusted runs. See the [Python contributor workflow](../development.md) and [installed-wheel testing decision](../../.agents/notes/implemented/testing/2026-08-23-installed-python-wheel-black-box-ci.md).
The installed-wheel smoke creates a clean virtual environment outside the checkout, proves the installed distribution and executable identities, then exercises default and customized SDK profiles, external plugins, MCP, native tools, direct JSON-RPC, committed snapshots, and the real provider on trusted runs. Its Office scenario relocates the complete target payload and converts DOCX with the required platform engine: native on macOS/Windows and WASM on Linux. See the [Python contributor workflow](../development.md) and [installed-wheel testing decision](../../.agents/notes/implemented/testing/2026-08-23-installed-python-wheel-black-box-ci.md).
+5 -1
View File
@@ -10,6 +10,8 @@ wheel 包会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python
生产可执行程序位于模块的 `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 包标签必须与载荷严格匹配;不发布 Windows arm64 wheel 包。
每个目标还要求 `<executable-stem>-office/`,其中 stem 不含 `.exe`。该目录包含完整的已安装 Office 包及其依赖,保留引擎资源、清单、许可证、源码清单与辅助程序权限。复制可执行文件时必须一并复制此目录。缺少目标引擎会使 sidecar 构建失败,错误会指出其 npm 包名与目标平台/架构。
仓库构建还会物化仅限开发的 `runtime/node/` 载体。它在系统 Node 22.19 或更高版本上运行 `node runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js`。系统不会自动选择它,而且 wheel 包与 sdist 均不包含它。
两种载体执行相同的 `dsh` 语法与随附 profile,包括独立的 `sdk-minimal` 配置树,以及包含前端产物的完整 `web` profile。私有 `dsh-python-runtime-closure` manifest(元数据清单)定义打包依赖闭包;不存在 Python 专用 Node 应用或检入的默认 `cordis.yml`。
@@ -27,6 +29,8 @@ wheel 包会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python
`dsh` 在显式指定的主目录下初始化随附 profile、组合其 bundle patch,并从可执行程序的虚拟文件系统加载内置插件。操作系统符号链接无法进入该文件系统,因此打包运行会在 `$DSH_HOME/profiles/node_modules` 下维护小型真实 ESM 代理包。每个代理复现运行时的显式导出项、记录原包身份,并重新导出虚拟模块 URL。因此,内置配置项与外部插件 peer 会共享同一个 Cordis/模块实例。原生共享库与 Windows ConPTY addon 会同其他原生 addon 一起打包;ripgrep 与 macOS PTY helper 仍是可执行伴随程序。
Python bootstrap 从相邻目录解析 Office kit,让原生辅助程序与 URL Worker 使用真实文件系统路径。kit 负责引擎选择与校验;Python bootstrap 不增加运行时下载或编译。
外部 profile 管理使用 `dsh plugin --profile <name> ...`。该命令要求 `PATH` 中存在 `pnpm`;普通 SDK/profile 运行不需要它。
## 构建与分发
@@ -35,4 +39,4 @@ wheel 包会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python
在仓库根目录运行 `pnpm exec tsx scripts/build-exe-for-python-sdk.ts`,会校验闭包、构建包、部署无符号链接的文件树、打包所选目标,并把可执行程序及伴随文件同步到本模块。`scripts/build-python-release.py` 按仓库根版本暂存发布形态的 wheel 包,并将 `deepseek-harness-sdk` 固定到完全相同的运行时版本。
已安装 wheel 包冒烟测试会在检出目录外创建干净的虚拟环境,验证分发物与可执行程序的来源,然后覆盖默认及自定义 SDK profile、外部插件、MCP、原生工具、直接 JSON-RPC、检入快照,以及可信运行中的真实提供方。另见 [Python 贡献者工作流](../development.zh.md) 与 [installed-wheel 测试决策](../../.agents/notes/implemented/testing/2026-08-23-installed-python-wheel-black-box-ci.zh.md)。
已安装 wheel 包冒烟测试会在检出目录外创建干净的虚拟环境,验证分发物与可执行程序的来源,然后覆盖默认及自定义 SDK profile、外部插件、MCP、原生工具、直接 JSON-RPC、检入快照,以及可信运行中的真实提供方。Office 场景会迁移完整的目标载荷目录,并使用所需的平台引擎转换 DOCX:macOS/Windows 使用原生引擎,Linux 使用 WASM。另见 [Python 贡献者工作流](../development.zh.md) 与 [installed-wheel 测试决策](../../.agents/notes/implemented/testing/2026-08-23-installed-python-wheel-black-box-ci.zh.md)。
+11
View File
@@ -73,6 +73,8 @@ class RuntimeBuildHook(BuildHookInterface):
f"unsupported DSH_RUNTIME_PLATFORM_TAG {platform_tag!r}; expected one of {supported}"
)
expected_executable = matches[0][1]
target = next(name for name, value in _PLATFORMS.items() if value[0] == platform_tag)
engine = "wasm" if target.startswith("linux-") else target.replace("win-", "win32-").replace("macos-", "darwin-")
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 []
@@ -84,6 +86,8 @@ class RuntimeBuildHook(BuildHookInterface):
)
if "-macos-" in expected_executable:
expected_files.append(f"{expected_executable}-spawn-helper")
office = runtime_dir / f"{expected_executable.removesuffix('.exe')}-office"
expected_files.append(office.name)
expected_files.sort()
found_files = [path.name for path in runtime_files]
if found_files != expected_files:
@@ -91,6 +95,13 @@ class RuntimeBuildHook(BuildHookInterface):
f"runtime wheel {platform_tag} payload must be {expected_files}; found {found_files}"
)
for executable in runtime_files:
if executable == office:
for required in ("@deepseek-ai/libreoffice-kit/package.json", f"@deepseek-ai/libreoffice-kit-{engine}/prebuilds.json"):
if not (office / "node_modules" / required).is_file():
raise RuntimeError(f"runtime Office dependency is missing: {office / required}")
continue
if not executable.is_file():
raise RuntimeError(f"runtime executable is not a file: {executable}")
if platform_tag != "win_amd64" and executable.stat().st_mode & stat.S_IXUSR == 0:
raise RuntimeError(f"runtime executable is not executable: {executable}")
build_data["pure_python"] = False
+1 -1
View File
@@ -22,7 +22,7 @@ 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-*"]
artifacts = ["src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*", "src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**"]
exclude = ["src/deepseek_harness_runtime/runtime/node"]
[tool.hatch.build.targets.wheel]
+14 -1
View File
@@ -1,6 +1,19 @@
#!/usr/bin/env node
/** Private entry owned by the Python single-file runtime packaging. */
import { fileURLToPath } from 'node:url'
import { registerHooks } from 'node:module'
import { isSea } from 'node:sea'
import { fileURLToPath, pathToFileURL } from 'node:url'
if (isSea()) {
// Office spawns executable helpers and URL workers; its complete package tree must be real files.
const parentURL = pathToFileURL(`${process.execPath.replace(/\.exe$/i, '')}-office/package.json`).href
registerHooks({
resolve(specifier, context, nextResolve) {
const office = specifier === '@deepseek-ai/libreoffice-kit' || specifier === '@deepseek-ai/libreoffice-kit/package.json'
return nextResolve(specifier, office ? { ...context, parentURL } : context)
},
})
}
const selectorName = 'DSH_SUBPROCESS_RUNNER'
const selection = process.env[selectorName]
@@ -57,7 +57,7 @@ def bundled_runtime_path() -> Path:
"""Absolute path of the bundled single-file runtime executable for the current platform.
Raises FileNotFoundError when the platform is unsupported, the executable
has not been placed into this package, the required ripgrep sidecar is
has not been placed into this package, the ripgrep or Office 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
@@ -88,6 +88,14 @@ def bundled_runtime_path() -> Path:
f"deepseek-harness-runtime-bin is missing the node-pty spawn helper at {helper}. "
+ _EXE_ACQUISITION_HINT
)
office = path.with_name(f"{path.name.removesuffix('.exe')}-office")
engine = "wasm" if tag.startswith("linux-") else tag.replace("win-", "win32-").replace("macos-", "darwin-")
for required in ("@deepseek-ai/libreoffice-kit/package.json", f"@deepseek-ai/libreoffice-kit-{engine}/prebuilds.json"):
if not (office / "node_modules" / required).is_file():
raise FileNotFoundError(
f"deepseek-harness-runtime-bin is missing the Office sidecar at {office}. "
+ _EXE_ACQUISITION_HINT
)
return path