feat(bundle): default Windows hosts to the pwsh shell stack

win32 hosts booting a shipped profile now get pwsh-local as the ctx.bash
executor and tool-pwsh as the shell tool through the base bundle's new
windows.cordis.patch.yml platform layer, injected by the launcher between
the bundle layers and the user layers on win32. bash-sandbox, tool-bash,
permission, and ui-permission are disabled there: the POSIX-only executor
cannot run on Windows, and dsh-permission requires a confining executor.
Overriding the default is a composition decision through the user's
cordis.patch.yml; there is no environment override channel.

apps/cli and dsh-base re-declare dsh-pwsh-local/dsh-tool-pwsh so the
profile module fallback links them for cold starts (the profiles rework
had dropped them from the CLI closure).

Promotes the windows-pwsh-default Agent Note from proposed to implemented
and documents the platform layer in the base bundle README.
This commit is contained in:
Huanqi Cao
2026-08-07 00:15:55 +08:00
parent 949d406086
commit 8ff75622c6
23 changed files with 306 additions and 104 deletions

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 packages/bundle/base/README.md
README.md: 301d397d4c87687b382665cf63af47ab5e3f85be
README.zh.md: f007bc817b6cbad84725fe8abe72549cf67d8cd7
README.md: a4f220c956f7f67d7810827d4488d54a071ad3d6
README.zh.md: eaf96f8c0640481163e7a1c1533a07e35ecc294f

View File

@@ -2,7 +2,9 @@
English | [中文](README.zh.md)
The shared dsh core as a profile bundle: [`cordis.patch.yml`](cordis.patch.yml) inserts every base plugin row — model adapters, tools, persistence, policy, settings/credentials, repository Plugins, telemetry — over the empty profile root, as the first layer of every profile's `dsh.profile.bundles` list. Later bundle layers (e.g. [`dsh-web-app`](../web-app/README.md)) and the user's profile `cordis.patch.yml` override these rows by id; a patch replaces a row's whole `config`, so mode-specific values live in mode bundles, not here. The package has no runtime API; the profile composer resolves the patch through the `dsh.bundle.patch` manifest field, never through code.
The shared dsh core as a profile bundle: [`cordis.patch.yml`](cordis.patch.yml) inserts every base plugin row — model adapters, tools, persistence, policy, settings/credentials, repository Plugins, telemetry — over the empty profile root, as the first layer of every profile's `dsh.profile.bundles` list. Later bundle layers (e.g. [`dsh-web-app`](../web-app/README.md)) and the user's profile `cordis.patch.yml` override these rows by id; a patch replaces a row's whole `config`, so mode-specific values live in mode bundles, not here. The package has no runtime API; the profile composer resolves the universal patch through the `dsh.bundle.patch` manifest field, and the launcher reads the Windows platform layer below from code on win32 hosts.
Windows hosts booting a shipped profile additionally receive [`windows.cordis.patch.yml`](windows.cordis.patch.yml): it disables the POSIX-only bash executor/tool and the permission stack (dsh-permission requires a confining executor), and inserts the PowerShell executor and tool (`@deepseek-ai/dsh-pwsh-local`, `@deepseek-ai/dsh-tool-pwsh`). The launcher applies it between the bundle layers and the user layers on win32 hosts; a Windows host that prefers the bash stack overrides these rows through its profile or home `cordis.patch.yml`. POSIX hosts never receive it.
The row set and its rationale are documented inline in the patch file; the [generated composition graph](../../../apps/cli/composition.md) renders it.
@@ -17,3 +19,4 @@ None directly; each inserted row's package owns its effect.
## Known Limitations and Deferred Work
- **A patch replaces whole row configs** — profile overrides must restate every field a row keeps; there is no deep-merge layer.
- **Windows loses the permission switcher** — `dsh-permission` hard-requires a confining `ctx.bash` executor, so the Windows platform layer disables `permission`/`ui-permission` with the bash stack. The fs tools keep the sandbox policy and the approval service, so file confinement and escalation still apply on Windows.

View File

@@ -2,7 +2,9 @@
[English](README.md) | 中文
以 profile 组合包形式交付的共享 dsh 核心:[`cordis.patch.yml`](cordis.patch.yml) 在空的 profile 根之上插入全部基础插件行——模型适配器、工具、持久化、策略、settingscredentials、repository 插件、遥测——作为每个 profile 的 `dsh.profile.bundles` 列表中的第一层。后续的组合包层(例如 [`dsh-web-app`](../web-app/README.md))和用户 profile 的 `cordis.patch.yml` 按 id 覆盖这些行patch 会替换目标行的整个 `config`,因此模式专属的值放在各模式组合包中,而不是这里。该包没有运行时 APIprofile 组合器通过 manifest元数据清单`dsh.bundle.patch` 字段解析 patch绝不通过代码
以 profile 组合包形式交付的共享 dsh 核心:[`cordis.patch.yml`](cordis.patch.yml) 在空的 profile 根之上插入全部基础插件行——模型适配器、工具、持久化、策略、settingscredentials、repository 插件、遥测——作为每个 profile 的 `dsh.profile.bundles` 列表中的第一层。后续的组合包层(例如 [`dsh-web-app`](../web-app/README.md))和用户 profile 的 `cordis.patch.yml` 按 id 覆盖这些行patch 会替换目标行的整个 `config`,因此模式专属的值放在各模式组合包中,而不是这里。该包没有运行时 APIprofile 组合器通过 manifest元数据清单`dsh.bundle.patch` 字段解析通用 patch启动器在 win32 主机上通过代码读取下面的 Windows 平台层
启动交付 profile 的 Windows 主机还会额外收到 [`windows.cordis.patch.yml`](windows.cordis.patch.yml):它禁用仅 POSIX 的 bash 执行器/工具与权限栈dsh-permission 要求有限权能力的执行器),并插入 PowerShell 执行器与工具(`@deepseek-ai/dsh-pwsh-local``@deepseek-ai/dsh-tool-pwsh`)。启动器在 win32 主机上把它应用于 bundle 层与用户层之间;偏好 bash 栈的 Windows 主机通过其 profile 或 home 的 `cordis.patch.yml` 覆盖这些行。POSIX 主机永远不会收到它。
行集合及其设计依据以行内注释写在 patch 文件里;[生成的组合图](../../../apps/cli/composition.md)负责渲染它。
@@ -17,3 +19,4 @@
## 已知限制与延期工作
- **patch 会替换整行 `config`**profile 覆盖必须重述该行需要保留的每个字段;不存在深度合并层。
- **Windows 上失去权限切换器**`dsh-permission` 硬性要求有限权能力的 `ctx.bash` 执行器,因此 Windows 平台层随 bash 栈一起禁用 `permission`/`ui-permission`。fs 工具保留 sandbox 策略与批准服务Windows 上的文件限制与升级仍然生效。

View File

@@ -16,6 +16,7 @@
"default": "./lib/invariant.js"
},
"./cordis.patch.yml": "./cordis.patch.yml",
"./windows.cordis.patch.yml": "./windows.cordis.patch.yml",
"./src/*": "./src/*",
"./package.json": "./package.json"
},
@@ -23,6 +24,7 @@
"lib/index.js",
"lib/invariant.js",
"cordis.patch.yml",
"windows.cordis.patch.yml",
"lib/types/**/*.d.ts"
],
"license": "BSD-3-Clause",
@@ -54,6 +56,7 @@
"@deepseek-ai/dsh-llm-retry": "workspace:^",
"@deepseek-ai/dsh-permission": "workspace:^",
"@deepseek-ai/dsh-plan-mode": "workspace:^",
"@deepseek-ai/dsh-pwsh-local": "workspace:^",
"@deepseek-ai/dsh-repeat-tool-guard": "workspace:^",
"@deepseek-ai/dsh-repository-plugin": "workspace:^",
"@deepseek-ai/dsh-sandbox-local": "workspace:^",
@@ -82,6 +85,7 @@
"@deepseek-ai/dsh-tool-fs": "workspace:^",
"@deepseek-ai/dsh-tool-fs-search": "workspace:^",
"@deepseek-ai/dsh-tool-goal": "workspace:^",
"@deepseek-ai/dsh-tool-pwsh": "workspace:^",
"@deepseek-ai/dsh-tool-ralph": "workspace:^",
"@deepseek-ai/dsh-tool-skill": "workspace:^",
"@deepseek-ai/dsh-tool-str-replace-editor": "workspace:^",

View File

@@ -0,0 +1,34 @@
# The dsh-base Windows platform layer: applied by the dsh launcher on win32
# hosts, between the bundle layers and the user layers, replacing the
# POSIX-only bash stack with the PowerShell stack. The launcher reads THIS
# file from the base bundle package (never through dsh.bundle.patch — that
# field names the one universal layer). A Windows host that prefers bash
# overrides the rows here through its profile or home cordis.patch.yml.
#
# Windows hosts cannot run the shipped bash executor (POSIX-only: hardcoded
# `bash -c` argv and process-group semantics), so the shipped Windows
# experience is PowerShell-native: pwsh-local backs `ctx.bash` and tool-pwsh
# is the model-facing shell tool. dsh-permission requires a confining
# executor (its presets bundle a sandbox mode the unconfined pwsh executor
# cannot honor), so the permission service and its client knob leave the
# Windows roster with the bash stack; the fs tools keep the sandbox policy
# and the approval service, so file confinement and escalation still apply.
- id: bash-sandbox
disabled: true
- id: tool-bash
disabled: true
- id: permission
disabled: true
- id: ui-permission
disabled: true
- insert:
- id: pwsh-local
name: '@deepseek-ai/dsh-pwsh-local'
- id: tool-pwsh
name: '@deepseek-ai/dsh-tool-pwsh'