feat(cua): ship Computer Use as an optional bundle in the Experimental plugins list

Refs #7514
This commit is contained in:
creatixchu
2026-10-29 13:40:54 +08:00
parent 2b1368f317
commit 3b544b0416
21 changed files with 66 additions and 78 deletions
+1
View File
@@ -107,6 +107,7 @@
"@deepseek-ai/dsh-experimental-liveshare": "workspace:*",
"@deepseek-ai/dsh-experimental-session-search": "workspace:*",
"@deepseek-ai/dsh-experimental-tool-worktree": "workspace:*",
"@deepseek-ai/dsh-cua-bundle": "workspace:*",
"@deepseek-ai/dsh-experimental-plugin-market-bundle": "workspace:*",
"@deepseek-ai/dsh-personalized-recommendations": "workspace:*",
"@deepseek-ai/dsh-experimental-forge-bundle": "workspace:*"
@@ -1,4 +1,4 @@
/** Cold pnpm requests exercise on-demand CUA dependency/platform metadata with inert package contents. */
/** Cold pnpm requests exercise shipped CUA dependency/platform metadata with inert package contents. */
import { createHash } from 'node:crypto'
import { createServer } from 'node:http'
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
@@ -37,14 +37,14 @@ it('fetches the macOS optional tarball only for Darwin, with an empty cache for
const cli = await readManifest('apps/cli')
const bundle = await readManifest('packages/experimental/cua-bundle')
const native = await readManifest('packages/experimental/cua-macos')
expect(cli.dependencies).not.toHaveProperty(bundleName)
expect(cli.dependencies).toHaveProperty(bundleName)
expect(bundle.dependencies).not.toHaveProperty(providerName)
expect(bundle.optionalDependencies).toEqual({ [providerName]: 'workspace:*' })
expect(native.os).toEqual(['darwin'])
const version = '1.0.0'
const bundleDependencies = Object.fromEntries(Object.keys(bundle.dependencies as Record<string, string>).map(name => [name, version]))
const manifests = [
{ name: cli.name, version },
{ name: cli.name, version, dependencies: { [bundleName]: version } },
{ name: bundleName, version, dependencies: bundleDependencies, optionalDependencies: { [providerName]: version } },
...Object.keys(bundleDependencies).map(name => ({ name, version })),
{ name: providerName, version, os: native.os, files: native.files },
@@ -102,13 +102,13 @@ it('fetches the macOS optional tarball only for Darwin, with an empty cache for
await new Promise<void>((resolve, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', resolve) })
const address = server.address()
if (!address || typeof address === 'string') throw new Error('fixture registry has no TCP address')
for (const target of ['darwin-base', 'darwin', 'win32', 'linux', 'linux-unrestricted']) {
for (const target of ['darwin', 'win32', 'linux', 'linux-unrestricted']) {
unrestricted = target === 'linux-unrestricted'
const project = join(root, target)
await mkdir(project)
await writeFile(join(project, 'package.json'), JSON.stringify({ private: true, dependencies: { [target === 'darwin-base' ? String(cli.name) : bundleName]: version } }))
await writeFile(join(project, 'package.json'), JSON.stringify({ private: true, dependencies: { [String(cli.name)]: version } }))
await writeFile(join(project, 'pnpm-workspace.yaml'), [
'autoInstallPeers: false', 'supportedArchitectures:', ` os: [${unrestricted ? 'linux' : target === 'darwin-base' ? 'darwin' : target}]`,
'autoInstallPeers: false', 'supportedArchitectures:', ` os: [${unrestricted ? 'linux' : target}]`,
' cpu: [arm64]', 'minimumReleaseAge: 0', '',
].join('\n'))
requests.length = 0
@@ -117,8 +117,8 @@ it('fetches the macOS optional tarball only for Darwin, with an empty cache for
`--config.registry=http://127.0.0.1:${address.port}/`, `--config.store-dir=${join(project, 'store')}`,
`--config.cache-dir=${join(project, 'cache')}`, `--config.state-dir=${join(project, 'state')}`,
], project)
expect(requests.includes(`/${bundleName}.tgz`)).toBe(target !== 'darwin-base')
expect(requests.includes('/@deepseek-ai/dsh-cua.tgz')).toBe(target !== 'darwin-base')
expect(requests).toContain(`/${bundleName}.tgz`)
expect(requests).toContain('/@deepseek-ai/dsh-cua.tgz')
expect(requests.includes(`/${providerName}.tgz`), `${target}: ${JSON.stringify(requests)}\n${output}`)
.toBe(target === 'darwin' || unrestricted)
}
+1 -1
View File
@@ -44,7 +44,7 @@ it('disables unsupported bundles, shows the Host restriction, and refuses direct
const names = [name]
await page.locator('[data-plugin-panel]').getByRole('button', { name: '更多', exact: true }).click()
const cua = page.locator('[data-plugin-package="@deepseek-ai/dsh-cua-bundle"]')
expect(await cua.count()).toBe(0)
expect(await cua.count()).toBe(process.platform === 'darwin' ? 1 : 0)
if (process.platform !== 'darwin') {
expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-cua-bundle'))
.toMatchObject({ listedByDefault: false, enabled: false, error: { code: 'unsupported-platform' } })
+8 -20
View File
@@ -53,22 +53,12 @@ it.skipIf(process.platform !== 'darwin').each([
await plugins.getByRole('button', { name: '更多', exact: true }).waitFor()
expect(await page.locator('[data-plugin-package="@deepseek-ai/dsh-cua-bundle"]').count()).toBe(0)
await plugins.getByRole('button', { name: '更多', exact: true }).click()
// The installation ships the bundle off; the Experimental plugins list offers it without an installation step.
const card = page.locator('[data-plugin-package="@deepseek-ai/dsh-cua-bundle"]')
expect(await card.count()).toBe(0)
expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-cua-bundle'))
.toMatchObject({ listedByDefault: false, enabled: false, installed: false })
await plugins.getByRole('button', { name: '返回插件', exact: true }).click()
const offerCua = async () => {
await plugins.getByRole('button', { name: '添加插件', exact: true }).click()
const dialog = page.getByRole('dialog', { name: '添加插件', exact: true })
await dialog.getByRole('textbox', { name: '包名或地址', exact: true }).fill('@deepseek-ai/dsh-cua-bundle')
await dialog.getByRole('button', { name: '安装', exact: true }).click()
const ready = page.getByRole('dialog', { name: '已安装', exact: true })
await ready.waitFor()
expect(await ready.getByText('无需下载,启用即可使用', { exact: true }).count()).toBe(0)
return ready.getByRole('button', { name: '立即启用', exact: true })
}
const enableNow = await offerCua()
await plugins.locator('[data-plugin-group="more"] [data-plugin-package="@deepseek-ai/dsh-cua-bundle"]').waitFor()
const listed = (await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-cua-bundle')
expect(listed).toMatchObject({ availability: 'installation', optional: true, enabled: false, installed: false })
expect(listed).not.toHaveProperty('listedByDefault')
let toggle = card.getByRole('switch', { name: '启用 Computer Use', exact: true })
const originalAgent = scaffold.ctx.agents.list()[0]!
const ptcAgent = (await scaffold.ctx.agents.create({
@@ -97,12 +87,10 @@ it.skipIf(process.platform !== 'darwin').each([
return applying
})
try {
await enableNow.click()
await expect.poll(() => enableNow.isEnabled()).toBe(false)
expect(await enableNow.getAttribute('aria-busy')).toBe('true')
expect(await card.count()).toBe(0)
await toggle.click()
await card.getByRole('status').getByText('正在应用 Computer Use 的更改', { exact: true }).waitFor()
await compareOrRefreshGolden(fileURLToPath(new URL('./expected/cua-permissions/enabling.expected.md', import.meta.url)),
await captureStableAria(page, '[data-install-phase="done"] button[aria-busy]', scaffold.workspaceCwd), webSnapshotMode())
await captureStableAria(page, '[data-plugin-package="@deepseek-ai/dsh-cua-bundle"] [role="status"]', scaffold.workspaceCwd), webSnapshotMode())
} finally {
enabling.resolve(undefined)
enableCall.mockRestore()
+1 -1
View File
@@ -42,7 +42,7 @@ it.skipIf(process.platform !== 'darwin')('keeps system requests pending until fr
})
resources.scaffold = scaffold
expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-cua-bundle'))
.toMatchObject({ listedByDefault: false, enabled: true, installed: true })
.toMatchObject({ availability: 'installation', enabled: true, installed: true })
const browser = await chromium.launch()
resources.browser = browser
const page = await newEnglishPage(browser), tripwire = watchConsole(page)
+6 -2
View File
@@ -856,9 +856,12 @@ describe('web e2e: plugin manager', () => {
.toBe(bundles.filter(bundle => bundle.name !== '@deepseek-ai/dsh-experimental-terminal-bundle'
&& bundle.name !== '@deepseek-ai/dsh-experimental-liveshare'
&& bundle.official && (bundle.listedByDefault !== false || bundle.enabled || bundle.installed)).length)
// Computer Use ships with the installation and is listed only on the macOS Hosts it supports.
const cuaSupported = process.platform === 'darwin'
expect(bundles.find(bundle => bundle.name === '@deepseek-ai/dsh-cua-bundle'))
.toMatchObject({ enabled: false, optional: false, availability: 'missing', listedByDefault: false })
expect(await panel.locator('[data-plugin-package="@deepseek-ai/dsh-cua-bundle"]').count()).toBe(0)
.toMatchObject({ enabled: false, optional: true, availability: 'installation', ...cuaSupported ? {} : { listedByDefault: false } })
expect(await panel.locator('[data-plugin-group="more"] [data-plugin-package="@deepseek-ai/dsh-cua-bundle"]').count())
.toBe(cuaSupported ? 1 : 0)
for (const name of ['@deepseek-ai/dsh-experimental-session-search', '@deepseek-ai/dsh-experimental-ralph-bundle']) {
expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === name))
.toMatchObject({ enabled: false, optional: true, availability: 'installation', listedByDefault: false })
@@ -876,6 +879,7 @@ describe('web e2e: plugin manager', () => {
['@deepseek-ai/dsh-experimental-forge-bundle', 1],
['@deepseek-ai/dsh-personalized-recommendations', 1],
['@deepseek-ai/dsh-experimental-inspector-profile', 1],
...cuaSupported ? [['@deepseek-ai/dsh-cua-bundle', 1]] : [],
['@deepseek-ai/dsh-experimental-tool-worktree', 1],
['@deepseek-ai/dsh-experimental-cot-translation-bundle', 1],
['@deepseek-ai/dsh-experimental-session-titles-bundle', 1],
+10 -7
View File
@@ -694,7 +694,6 @@ async function toggleOptionalBundles(page: Page): Promise<void> {
})
}
return {
cua: bundles.filter(entry => entry.name === '@deepseek-ai/dsh-cua-bundle'),
optional: bundles.filter(entry => entry.optional).map(entry => ({
name: entry.name, enabled: entry.enabled, availability: entry.availability, error: entry.error ?? null,
title: typeof entry.meta?.title, icon: typeof entry.meta?.icon, metaError: entry.meta?.error ?? null,
@@ -706,16 +705,20 @@ async function toggleOptionalBundles(page: Page): Promise<void> {
})
expect(result.optional.map(entry => entry.name).sort()).toEqual([...OPTIONAL_BUNDLES].sort())
expect(result.optional.filter(entry => entry.enabled || entry.availability !== 'installation')).toEqual([])
expect(result.optional.filter(entry => entry.error !== null)).toEqual([])
expect(result.cua).toHaveLength(1)
expect(result.cua[0]).toMatchObject({ name: '@deepseek-ai/dsh-cua-bundle', optional: false,
availability: 'missing', error: { code: 'unsupported-platform' } })
expect(result.optional.filter(entry => entry.error !== null)).toEqual([
expect.objectContaining({ name: '@deepseek-ai/dsh-cua-bundle', error: { code: 'unsupported-platform' } }),
])
// Metadata resolves through the Worker's Node internal modules: every optional bundle shows its title and icon.
expect(result.optional.filter(entry => entry.metaError !== null || entry.title !== 'object' || entry.icon !== 'string')).toEqual([])
expect(result.inventoryErrors).toEqual([])
console.info(`preview boot: optional bundle toggles ${JSON.stringify(result.toggles.map(({ name, enable, disable, error }) => ({ name, enable, disable, error })))}`)
expect(result.toggles.find(toggle => toggle.name === '@deepseek-ai/dsh-cua-bundle')).toBeUndefined()
const supported = result.toggles
expect(result.toggles.find(toggle => toggle.name === '@deepseek-ai/dsh-cua-bundle')).toMatchObject({
enable: 'failed', disable: 'applied', error: { code: 'unsupported-platform' },
changed: 0, inactive: [], restored: true,
})
// The packed worker composition excludes LiveShare from its generic toggles; plugin-manager.e2e.ts
// covers that bundle's enable/disable path in the ordinary Web scaffold.
const supported = result.toggles.filter(toggle => toggle.name !== '@deepseek-ai/dsh-cua-bundle')
expect(supported.filter(toggle => toggle.enable !== 'applied' || toggle.disable !== 'applied')
.map(({ name, enable, disable }) => ({ name, enable, disable }))).toEqual([])
// Each bundle changes Loader rows, every enabled row it changes runs, and switching it off restores the prior rows.
@@ -12,5 +12,5 @@
en: 1552866718133b10
zh: 1c760c5c2d5cfc0b
/authorize-the-computer-use-helper/migration:
en: a79e5995415ff456
zh: 6f818a092e53af2c
en: 2a28385e24468734
zh: 725c1856a604bc0c
@@ -13,7 +13,7 @@ macOS Computer Use runs as `DSH Computer Use.app`, launched through LaunchServic
## Migration
1. Computer Use now installs on demand. In **Plugins → Add plugin**, install `@deepseek-ai/dsh-cua-bundle` and enable it; profiles that previously selected the shipped copy need this installation. Restart DSH if requested. In the Computer Use plugin page, grant Accessibility and Screen Recording access to `DSH Computer Use.app` when macOS requests it.
1. Restart DSH after upgrading the Computer Use package. In the Computer Use plugin page, grant Accessibility and Screen Recording access to `DSH Computer Use.app` when macOS requests it.
2. Remove an obsolete `helperPath` override or `DSH_CUA_HELPER` value to use automatic preparation. For a custom build, point it to the executable at `DSH Computer Use.app/Contents/MacOS/dsh-cua-native` inside the complete application bundle.
3. Confirm that the permission page identifies `DSH Computer Use.app` and both permissions are allowed before resuming native application tasks. Target-application consent remains required.
4. If a terminal or Desktop launcher was granted these permissions only for Computer Use, revoke those obsolete grants in System Settings. Authorizing the helper does not revoke other applications’ existing permissions; programs the model runs still follow their launcher’s system permissions and the DSH sandbox policy.
@@ -13,7 +13,7 @@ macOS Computer Use 通过 LaunchServices 以 `DSH Computer Use.app` 运行。终
## 迁移
1. Computer Use 改为按需安装。在“插件 → 添加插件”中安装 `@deepseek-ai/dsh-cua-bundle` 并启用;此前选中过内置副本的 profile 也需完成这次安装。按提示重启 DSH。在 Computer Use 插件页按 macOS 提示,给 `DSH Computer Use.app` 授予辅助功能和屏幕录制权限。
1. 升级 Computer Use 包后重启 DSH。在 Computer Use 插件页按 macOS 提示,给 `DSH Computer Use.app` 授予辅助功能和屏幕录制权限。
2. 删除过时的 `helperPath` 覆盖配置或 `DSH_CUA_HELPER` 值,使用自动准备。使用自定义构建时,将其指向完整应用包内的 `DSH Computer Use.app/Contents/MacOS/dsh-cua-native` 可执行文件。
3. 恢复原生应用任务前,确认权限页显示 `DSH Computer Use.app`,且两项权限均已允许。具体目标应用仍需另行许可。
4. 若终端或 Desktop 启动器的这两项权限只用于 Computer Use,可在系统设置中撤销这些旧授权。给 helper 授权不会撤销其他应用已有的权限;模型运行的程序仍遵循启动器的系统权限和 DSH 沙箱策略。
@@ -1256,7 +1256,6 @@ describe('PluginManagerPage', () => {
})
it.each([
'@deepseek-ai/dsh-cua-bundle',
'@deepseek-ai/dsh-experimental-session-search',
'@deepseek-ai/dsh-experimental-ralph-bundle',
'@acme/shipped-exploration',
@@ -9,14 +9,14 @@
en: 9084fb48d0f6489c
zh: ce692972d91cf663
/deepseek-ai-dsh-cua-bundle/summary:
en: 5f213491dd724c91
zh: 228439436d3b339c
en: 0d93f44a8ce7404c
zh: 6a73ed42d0efc9ea
/deepseek-ai-dsh-cua-bundle/table-of-contents:
en: b563e4ec4727d0de
zh: d0228da978238e05
/deepseek-ai-dsh-cua-bundle/use-this-package:
en: 92b549c20b7b8e63
zh: 90df835c4e9bac75
en: 1c54bec900429732
zh: c062f2515dc3e41a
/deepseek-ai-dsh-cua-bundle/understand-the-implementation:
en: b1011db52cfc17cd
zh: 6fa8798fedc5c0b6
@@ -39,8 +39,8 @@
en: 417c40acd93df532
zh: 69cc5cf7140c75a9
/deepseek-ai-dsh-cua-bundle/known-limitations-and-deferred-work:
en: 7d91694e2f6b111e
zh: 54bcc0cef9496ed6
en: f2362542e43a1946
zh: c45ca90c66ce6a48
/deepseek-ai-dsh-cua-bundle/known-limitations-and-deferred-work/dev-note:
en: 0a1253c6f7b5e8b9
zh: ce96645b3e75874e
+6 -5
View File
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
Enable macOS Computer Use from Plugins for existing and new PTC sessions. Windows support is in development. This bundle remains in `experimental` until that support is complete, then moves to the `computer-use` group. It is off by default and hidden from the default plugin lists until enabled or separately installed; disabled profiles prepare no native components and register neither CUA tools nor their model guidance.
Enable macOS Computer Use from Plugins for existing and new PTC sessions. Windows support is in development. This bundle remains in `experimental` until that support is complete, then moves to the `computer-use` group. It ships with DSH switched off and appears in the Experimental plugins list on macOS Hosts; disabled profiles prepare no native components and register neither CUA tools nor their model guidance.
## Table of Contents
@@ -24,7 +24,7 @@ Enable macOS Computer Use from Plugins for existing and new PTC sessions. Window
<a id="use-this-package"></a>
## Use this package
In macOS Desktop, open **Plugins → Add plugin**, enter `@deepseek-ai/dsh-cua-bundle`, choose **Install**, then **Enable now**. DSH installs the official version matching its runtime into the profile. Published packages contain the signed and notarized helper; users need no compiler. Source Web and development Desktop link the workspace bundle and prepare an ad-hoc helper when enabled. Open Computer Use details, choose PTC if needed, and grant Accessibility and Screen Recording to `DSH Computer Use.app`. Disabled installed bundles remain available for management. For source Web, run these commands from the repository root:
On macOS, open **Plugins → More** and switch on Computer use in the Experimental plugins list. The bundle ships with DSH and updates with it, so enabling it downloads nothing. Published packages contain the signed and notarized helper; users need no compiler. Source Web and development Desktop prepare an ad-hoc helper when enabled. Open Computer Use details, choose PTC if needed, and grant Accessibility and Screen Recording to `DSH Computer Use.app`. An enabled bundle also appears in the main plugin list; switching it off returns it to the Experimental plugins list only. For source Web, run these commands from the repository root:
```sh
pnpm run build
@@ -33,11 +33,11 @@ pnpm dsh web
For the source Desktop launcher and its separate development profile, follow [Desktop development](../../../apps/desktop/README.md). Enable Computer Use in each profile that needs it.
The switch saves bundle selection in the profile’s `package.json`. Computer Use is installed only in PTC sessions. Enabling through Add plugin, a visible card, or its detail page offers setup guidance when system permissions need attention. The detail page offers **Set to PTC** for the new-session default; existing sessions keep their preset. The switch leaves PTC execution mode and other settings unchanged. The detail page’s **Use persistent mode** action separately enables in-memory state across PTC calls; its effects and reload behavior are described in the [permission page](../cua/README.md). Native preparation runs when the provider loads and reuses the source-hashed executable when available.
The switch saves bundle selection in the profile’s `package.json`. Computer Use is installed only in PTC sessions. Enabling through its card or detail page offers setup guidance when system permissions need attention. The detail page offers **Set to PTC** for the new-session default; existing sessions keep their preset. The switch leaves PTC execution mode and other settings unchanged. The detail page’s **Use persistent mode** action separately enables in-memory state across PTC calls; its effects and reload behavior are described in the [permission page](../cua/README.md). Native preparation runs when the provider loads and reuses the source-hashed executable when available.
Disabling unloads the provider and withdraws CUA tools from its Agent scopes. Runtime configuration, the new-session default and saved grants remain.
Computer Use is available only on a macOS DSH Host. The native provider is an optional dependency installed only on macOS; the bundle and its shared libraries install on demand. Other Hosts hide the bundle from default plugin lists and model recommendations and refuse enablement before saving settings. Explicit profile dependencies and saved selections remain visible for management. An already selected bundle is skipped at startup with a diagnostic and remains available for deselection; saved user settings remain. A browser on another operating system can connect to a supported Mac Host.
Computer Use is available only on a macOS DSH Host. The native provider is an optional dependency installed only on macOS; shared CUA and Client packages remain in the installation. Other Hosts hide the bundle from default plugin lists and model recommendations and refuse enablement before saving settings. Explicit profile dependencies and saved selections remain visible for management. An already selected bundle is skipped at startup with a diagnostic and remains available for deselection; saved user settings remain. A browser on another operating system can connect to a supported Mac Host.
If preparation fails, the saved selection remains and CUA operations stay unavailable. Refresh or reopen the plugin page to read the component diagnostic, correct its cause, then restart DSH.
@@ -85,7 +85,8 @@ CUA activation and removal change the PTC SDK and system guidance; subsequent re
<a id="known-limitations-and-deferred-work"></a>
- First installation requires a reachable registry carrying the matching DSH version. System permissions require the user’s approval in macOS; installation does not grant them.
- System permissions require the user’s approval in macOS; enabling the bundle does not grant them.
- A profile that installed the bundle from a registry keeps that dependency. The installation’s copy loads instead, and the plugin page offers no removal for the redundant dependency.
- PTC execution is shared by the profile and is configured independently. A Host without HMR applies saved changes at restart.
<a id="dev-note"></a>
@@ -9,7 +9,7 @@ kind: "package-bundle"
## 概述
从插件页为已有和新建 PTC 会话开启 macOS Computer Use。Windows 支持正在开发中。本组合包暂放在 `experimental`,待 Windows 支持完成后迁回 `computer-use` 组。默认关闭,启用或单独安装前不在默认插件列表中显示;关闭时不准备本机组件、不注册 CUA 工具或添加其模型指引。
从插件页为已有和新建 PTC 会话开启 macOS Computer Use。Windows 支持正在开发中。本组合包暂放在 `experimental`,待 Windows 支持完成后迁回 `computer-use` 组。随 DSH 提供且默认关闭,在 macOS Host 的实验性插件列表中显示;关闭时不准备本机组件、不注册 CUA 工具或添加其模型指引。
## 目录
@@ -24,7 +24,7 @@ kind: "package-bundle"
<a id="use-this-package"></a>
## 使用本包
在 macOS Desktop 的“插件 → 添加插件”中输入 `@deepseek-ai/dsh-cua-bundle`,点击“安装”,再点击“立即启用”。DSH 将与当前运行时版本匹配的官方插件安装到 profile。发布包包含已签名和公证的 helper,用户无需编译工具。源码 Web 和开发 Desktop 链接工作区组合包,启用时准备临时签名的 helper。打开 Computer Use 详情,按需设置 PTC,并为 `DSH Computer Use.app` 授予辅助功能和屏幕录制权限。已安装的组合包关闭后仍可管理。源码 Web 在仓库根目录运行以下命令:
在 macOS 上打开“插件 → 更多”,在实验性插件列表中开启 Computer Use。组合包随 DSH 提供并随之升级,开启时无需下载。发布包包含已签名和公证的 helper,用户无需编译工具。源码 Web 和开发 Desktop 在开启时准备临时签名的 helper。打开 Computer Use 详情,按需设置 PTC,并为 `DSH Computer Use.app` 授予辅助功能和屏幕录制权限。开启后组合包也会出现在插件主列表中,关闭后只留在实验性插件列表。源码 Web 在仓库根目录运行以下命令:
```sh
pnpm run build
@@ -33,11 +33,11 @@ pnpm dsh web
源码 Desktop 的启动方式和独立开发配置档见[桌面开发说明](../../../apps/desktop/README.zh.md)。需要使用 Computer Use 的配置档分别开启该功能。
开关将组合包选择保存到 profile 的 `package.json`。Computer Use 仅安装在 PTC 会话中。通过「添加插件」、可见卡片或详情页启用时,系统权限未就绪会显示设置引导。详情页提供“设为 PTC”按钮来修改新会话默认模式,已有会话保留原 preset。开关保持 PTC 执行方式和其他设置不变。详情页的“设为持久化”按钮单独开启 PTC 跨调用的内存状态保留,作用范围和重载行为见[权限页面](../cua/README.zh.md)。提供方加载时准备本机组件,已有与源码摘要匹配的可执行文件时直接复用。
开关将组合包选择保存到 profile 的 `package.json`。Computer Use 仅安装在 PTC 会话中。通过卡片或详情页启用时,系统权限未就绪会显示设置引导。详情页提供“设为 PTC”按钮来修改新会话默认模式,已有会话保留原 preset。开关保持 PTC 执行方式和其他设置不变。详情页的“设为持久化”按钮单独开启 PTC 跨调用的内存状态保留,作用范围和重载行为见[权限页面](../cua/README.zh.md)。提供方加载时准备本机组件,已有与源码摘要匹配的可执行文件时直接复用。
关闭会卸载提供方,并从其 Agent 作用域中撤回 CUA 工具。执行器配置、新会话默认值和已保存的授权保留。
Computer Use 仅支持 macOS DSH Host。原生提供方是仅在 macOS 安装的可选依赖,组合包和共享库均按需安装。其他 Host 默认不在插件列表和模型推荐中展示此组合包,并在保存设置前拒绝启用。profile 显式安装的依赖和已保存的选择仍保留管理入口。已选中的组合包会在启动时跳过并报告原因,仍可取消选择;已保存的用户设置保留。其他操作系统上的浏览器可以连接受支持的 Mac Host。
Computer Use 仅支持 macOS DSH Host。原生提供方是仅在 macOS 安装的可选依赖,共享 CUA 和 Client 包仍随安装提供。其他 Host 默认不在插件列表和模型推荐中展示此组合包,并在保存设置前拒绝启用。profile 显式安装的依赖和已保存的选择仍保留管理入口。已选中的组合包会在启动时跳过并报告原因,仍可取消选择;已保存的用户设置保留。其他操作系统上的浏览器可以连接受支持的 Mac Host。
准备失败时,已保存的选择保留,CUA 操作不可用。刷新或重新打开插件页查看组件诊断,修复后重启 DSH。
@@ -85,7 +85,8 @@ CUA 生效和卸载会改变 PTC SDK 与系统指引,后续请求使用更新
<a id="known-limitations-and-deferred-work"></a>
- 首次安装需要能访问提供匹配 DSH 版本的注册表。系统权限需用户在 macOS 中确认,安装插件不会自动授予权限。
- 系统权限需用户在 macOS 中确认,开启组合包不会自动授予权限。
- 从注册表安装过组合包的 profile 会保留该依赖。加载的是安装目录中的副本,插件页不提供移除这条多余依赖的操作。
- PTC 执行方式由 profile 共享,需单独配置。未启用 HMR 的 Host 在重启时应用已保存的变更。
<a id="dev-note"></a>
@@ -35,7 +35,6 @@
"license": "MIT",
"dsh": {
"bundle": {
"listedByDefault": false,
"patch": "./cordis.patch.yml",
"platforms": [
"darwin"
@@ -54,6 +54,7 @@ export const DEFAULT_PROFILE_BUNDLES: readonly string[] = ['@deepseek-ai/dsh-bas
*/
export const OPTIONAL_BUNDLES: readonly string[] = [
'@deepseek-ai/dsh-personalized-recommendations',
'@deepseek-ai/dsh-cua-bundle',
'@deepseek-ai/dsh-experimental-session-search',
'@deepseek-ai/dsh-experimental-ralph-bundle',
'@deepseek-ai/dsh-experimental-terminal-bundle',
@@ -74,5 +75,4 @@ export const OPTIONAL_BUNDLES: readonly string[] = [
export const ON_DEMAND_BUNDLES: readonly string[] = [
'@deepseek-ai/dsh-subagent-claude-code',
'@deepseek-ai/dsh-subagent-codex',
'@deepseek-ai/dsh-cua-bundle',
]
@@ -20,14 +20,4 @@ export const OFFICIAL_ON_DEMAND_CATALOG: readonly OfficialBundleCatalogEntry[] =
icon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB4PSIxNC45ODkzIiB5PSIxNS4xODc3IiB3aWR0aD0iMTIuMjM2NSIgaGVpZ2h0PSIxMi4yMzY1IiByeD0iMiIgZmlsbD0idXJsKCNkc2hfcGx1Z2luX2FydF9SMGEpIiBmaWxsLW9wYWNpdHk9IjAuOCI+PC9yZWN0PjxyZWN0IHg9IjguODcxMDkiIHk9IjkuMDY5NyIgd2lkdGg9IjEyLjIzNjUiIGhlaWdodD0iMTIuMjM2NSIgcng9IjIiIGZpbGw9InVybCgjZHNoX3BsdWdpbl9hcnRfUjBiKSIgZmlsbC1vcGFjaXR5PSIwLjgiPjwvcmVjdD48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYSIgeDE9IjIxLjEwNzUiIHkxPSIxNS4xODc3IiB4Mj0iMjEuMTA3NSIgeTI9IjI3LjQyNDMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDVFN0E0Ij48L3N0b3A+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDU5MDlEIj48L3N0b3A+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImRzaF9wbHVnaW5fYXJ0X1IwYiIgeDE9IjE0Ljk4OTQiIHkxPSI5LjA2OTciIHgyPSIxNC45ODk0IiB5Mj0iMjEuMzA2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiM2OUI5RkYiPjwvc3RvcD48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMjRERTIiPjwvc3RvcD48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48L3N2Zz4K',
},
},
{
packageName: '@deepseek-ai/dsh-cua-bundle',
platforms: ['darwin'],
listedByDefault: false,
meta: {
title: { 'de': 'Computernutzung', 'en': 'Computer use', 'es': 'Uso de la computadora', 'fr': 'Utilisation de l\'ordinateur', 'ja': 'Computer Use', 'pt': 'Uso do computador', 'ru': '\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0430', 'zh': 'Computer Use' },
description: { 'de': 'Unterst\u00FCtzt derzeit macOS; Die Windows-Unterst\u00FCtzung befindet sich in der Entwicklung. L\u00E4dt die Computernutzung f\u00FCr bestehende und neue PTC-Sitzungen. Wechseln Sie in den PTC-Modus und erteilen Sie die Berechtigungen f\u00FCr Barrierefreiheit und Bildschirmaufzeichnung, um ihn zu verwenden.', 'en': 'Currently supports macOS; Windows support is in development. Loads computer use for existing and new PTC sessions. Switch to PTC mode and grant Accessibility and Screen Recording permissions to use it.', 'es': 'Actualmente es compatible con macOS; El soporte para Windows est\u00E1 en desarrollo. Carga el uso de la computadora para sesiones PTC nuevas y existentes. Cambie al modo PTC y otorgue permisos de Accesibilidad y Grabaci\u00F3n de pantalla para usarlo.', 'fr': 'Prend actuellement en charge macOS\u00A0; La prise en charge de Windows est en cours de d\u00E9veloppement. Charge l\'utilisation de l\'ordinateur pour les sessions PTC existantes et nouvelles. Passez en mode PTC et accordez les autorisations d\u2019accessibilit\u00E9 et d\u2019enregistrement d\u2019\u00E9cran pour l\u2019utiliser.', 'ja': '\u73FE\u5728\u306F macOS \u306E\u307F\u5BFE\u5FDC\u3057\u3001Windows \u5BFE\u5FDC\u306F\u958B\u767A\u4E2D\u3067\u3059\u3002\u65E2\u5B58\u304A\u3088\u3073\u65B0\u898F\u306E PTC \u30BB\u30C3\u30B7\u30E7\u30F3\u306B Computer Use \u3092\u8AAD\u307F\u8FBC\u307F\u307E\u3059\u3002PTC \u30E2\u30FC\u30C9\u306B\u5207\u308A\u66FF\u3048\u3001\u30A2\u30AF\u30BB\u30B7\u30D3\u30EA\u30C6\u30A3\u3068\u753B\u9762\u53CE\u9332\u306E\u6A29\u9650\u3092\u8A31\u53EF\u3057\u3066\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002', 'pt': 'Atualmente suporta macOS; O suporte Windows est\u00E1 em desenvolvimento. Carrega o uso do computador para sess\u00F5es PTC novas e existentes. Mude para o modo PTC e conceda permiss\u00F5es de acessibilidade e grava\u00E7\u00E3o de tela para us\u00E1-lo.', 'ru': '\u0412 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0435\u0435 \u0432\u0440\u0435\u043C\u044F \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F macOS; \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430 Windows \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u043A\u0435. \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0430 \u0434\u043B\u044F \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445 \u0438 \u043D\u043E\u0432\u044B\u0445 \u0441\u0435\u0430\u043D\u0441\u043E\u0432 PTC. \u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u0435\u0441\u044C \u0432 \u0440\u0435\u0436\u0438\u043C PTC \u0438 \u043F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u0438 \u0437\u0430\u043F\u0438\u0441\u044C \u044D\u043A\u0440\u0430\u043D\u0430 \u0434\u043B\u044F \u0435\u0433\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F.', 'zh': '\u76EE\u524D\u4EC5\u652F\u6301 macOS\uFF0CWindows \u652F\u6301\u6B63\u5728\u5F00\u53D1\u4E2D\u3002\u4E3A\u5DF2\u6709\u53CA\u65B0\u5EFA PTC \u4F1A\u8BDD\u52A0\u8F7D Computer Use\u3002\u8BF7\u5207\u6362\u5230 PTC \u6A21\u5F0F\u6765\u4F7F\u7528\uFF0C\u5E76\u6388\u4E88\u8F85\u52A9\u529F\u80FD\u548C\u5C4F\u5E55\u5F55\u5236\u6743\u9650\u3002' },
icon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzYiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCAzNiAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8IS0tCiAgICBDb21wdXRlciBVc2UgcGx1Z2luIGljb24uCiAgICBBZGFwdGVkIGZyb20gTHVjaWRlICJtb3VzZS1wb2ludGVyLWNsaWNrIiAoaHR0cHM6Ly9sdWNpZGUuZGV2L2ljb25zL21vdXNlLXBvaW50ZXItY2xpY2spLgogICAgQ2hhbmdlczogc29saWQtZmlsbGVkIHBvaW50ZXIsIHByb2plY3QgcGFsZXR0ZSwgMzZ4MzYgY2FudmFzLgoKICAgIElTQyBMaWNlbnNlCiAgICBDb3B5cmlnaHQgKGMpIDIwMjYgTHVjaWRlIEljb25zIGFuZCBDb250cmlidXRvcnMKICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9sdWNpZGUtaWNvbnMvbHVjaWRlL2Jsb2IvbWFpbi9MSUNFTlNFCgogICAgUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55CiAgICBwdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQsIHByb3ZpZGVkIHRoYXQgdGhlIGFib3ZlCiAgICBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIGFwcGVhciBpbiBhbGwgY29waWVzLgogICAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTCiAgICBXSVRIIFJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GCiAgICBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1IgQkUgTElBQkxFIEZPUgogICAgQU5ZIFNQRUNJQUwsIERJUkVDVCwgSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUwogICAgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOCiAgICBBQ1RJT04gT0YgQ09OVFJBQ1QsIE5FR0xJR0VOQ0UgT1IgT1RIRVIgVE9SVElPVVMgQUNUSU9OLCBBUklTSU5HIE9VVCBPRgogICAgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IgUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS4KICAtLT4KICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0LjAzNiA0LjAzNikgc2NhbGUoMS4yMjAxKSI+CiAgICA8cGF0aCBkPSJNOS4wMzcgOS42OWEuNDk4LjQ5OCAwIDAgMSAuNjUzLS42NTNsMTEgNC41YS41LjUgMCAwIDEtLjA3NC45NDlsLTQuMzQ5IDEuMDQxYTEgMSAwIDAgMC0uNzQuNzM5bC0xLjA0IDQuMzVhLjUuNSAwIDAgMS0uOTUuMDc0eiIgZmlsbD0idXJsKCNnKSIgc3Ryb2tlPSJ1cmwoI2cpIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIC8+CiAgICA8cGF0aCBkPSJNMTQgNC4xIDEyIDYiIHN0cm9rZT0iIzUxQ0ZEQiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+CiAgICA8cGF0aCBkPSJtNS4xIDgtMi45LS44IiBzdHJva2U9IiM1MUNGREIiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiAvPgogICAgPHBhdGggZD0ibTYgMTItMS45IDIiIHN0cm9rZT0iIzUxQ0ZEQiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+CiAgICA8cGF0aCBkPSJNNy4yIDIuMiA4IDUuMSIgc3Ryb2tlPSIjNTFDRkRCIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8L2c+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImciIHgxPSI5IiB5MT0iOSIgeDI9IjIxIiB5Mj0iMjEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iIzg2QjhGNSIgLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNTI2OUUxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+Cjwvc3ZnPgo=',
},
},
]
@@ -4,10 +4,8 @@ import { describe, expect, it } from 'vitest'
import { OFFICIAL_ON_DEMAND_CATALOG, ON_DEMAND_BUNDLES, PROFILE_TEMPLATES } from '../src/index.ts'
describe('Official on-demand catalog', () => {
it('offers native subagents and default-hidden Computer Use with offline metadata', () => {
expect(ON_DEMAND_BUNDLES).toEqual(['@deepseek-ai/dsh-subagent-claude-code', '@deepseek-ai/dsh-subagent-codex', '@deepseek-ai/dsh-cua-bundle'])
expect(OFFICIAL_ON_DEMAND_CATALOG.find(entry => entry.packageName === '@deepseek-ai/dsh-cua-bundle'))
.toMatchObject({ platforms: ['darwin'], listedByDefault: false })
it('offers exactly the two native subagent integrations with offline localized metadata', () => {
expect(ON_DEMAND_BUNDLES).toEqual(['@deepseek-ai/dsh-subagent-claude-code', '@deepseek-ai/dsh-subagent-codex'])
expect(OFFICIAL_ON_DEMAND_CATALOG.map(entry => entry.packageName)).toEqual(ON_DEMAND_BUNDLES)
for (const entry of OFFICIAL_ON_DEMAND_CATALOG) {
expect(entry.meta.icon).toMatch(/^data:image\/svg\+xml;base64,/)
+3
View File
@@ -336,6 +336,9 @@ importers:
'@deepseek-ai/dsh-cordis-client-runner':
specifier: workspace:*
version: link:../../packages/extensions/cordis-client-runner
'@deepseek-ai/dsh-cua-bundle':
specifier: workspace:*
version: link:../../packages/experimental/cua-bundle
'@deepseek-ai/dsh-experimental-agent-team-profile':
specifier: workspace:*
version: link:../../packages/experimental/agent-team-profile
+2 -1
View File
@@ -133,7 +133,8 @@ describe('catalog and local closure', () => {
// A vendor package keeps its own version line, so a run must not assume one shared version.
expect(packages.get('@deepseek-ai/cordis')?.manifest.version)
.not.toBe(packages.get('@deepseek-ai/dsh-brand')?.manifest.version)
expect(selection.foreignTargets).toEqual(process.platform === 'darwin' ? [] : ['@deepseek-ai/dsh-experimental-cua-macos'])
// Nothing in this closure is built for another platform, on any host.
expect(selection.foreignTargets).toEqual([])
})
it('follows install, optional, and required peer edges but not optional peers', () => {
File diff suppressed because one or more lines are too long