mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
feat(web): hide persistent terminal bundle controls (#6753)
Co-authored-by: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com>
This commit is contained in:
1 parent
b526b87520
commit
e819a7126b
18 files changed
+117
-39
No files matched your search
@@ -9,8 +9,8 @@
|
||||
en: dc43ba84345e1405
|
||||
zh: dbc03572ab7710d2
|
||||
/agent-note-ship-optional-bundles-with-the-installation/decision:
|
||||
en: 5210b3b746cfee78
|
||||
zh: f1907f4807ae0098
|
||||
en: 1362533f342b31f4
|
||||
zh: 90689262acefb43d
|
||||
/agent-note-ship-optional-bundles-with-the-installation/alternatives-considered:
|
||||
en: 95b48b61757f1f13
|
||||
zh: e9fb2d6ea492a4bc
|
||||
|
||||
@@ -10,7 +10,7 @@ The Web plugin page manages only the bundles a person installed into the profile
|
||||
|
||||
## Decision
|
||||
|
||||
The launcher names in `OPTIONAL_BUNDLES` (`packages/boot/app-boot/src/profile.ts`, beside the profile templates) the bundles the installation ships for a person to switch on. Each must be a runtime dependency of `apps/cli` that declares `dsh.bundle.patch`, and no shipped profile template selects it. The plugin manager's `listBundles` reports such a bundle as `optional`: switched off until selected, never removable, resolved from the installation like any installation-supplied bundle. The Web plugin page opens its Official group with the optional bundles, tagged experimental when the package is experimental, ahead of the profile's own installed bundles.
|
||||
The launcher names in `OPTIONAL_BUNDLES` (`packages/boot/app-boot/src/profile.ts`, beside the profile templates) the bundles the installation ships for a person to switch on. Each must be a runtime dependency of `apps/cli` that declares `dsh.bundle.patch`, and no shipped profile template selects it. The plugin manager's `listBundles` reports such a bundle as `optional`: switched off until selected, never removable, resolved from the installation like any installation-supplied bundle. The Web plugin page presents offered optional bundles in its Official group, tagged experimental when the package is experimental, ahead of the profile's own installed bundles. The [persistent-terminal bundle](../../../../packages/experimental/terminal-bundle/README.md) remains available to the Host but has no page switch, even when enabled; its existing profile selection remains intact.
|
||||
|
||||
Default-product isolation keeps its rules with one declared exception: an optional bundle's dependency graph is outside the default product. The static gate skips the `dependencies` edge from `@deepseek-ai/dsh` to a listed bundle and still rejects a runtime import, a shipped composition, a preset, or a default template that names it, an experimental dependency the list does not name, and a listed name that is not a runtime dependency or not a bundle. The workspace-constraints check accepts the same `dependencies` edges and no other runtime section, and the packed-install release check skips them from the installed entry package while requiring each listed bundle to be installed.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Web 插件页只管理用户装进 profile 的组合包。像 Agent Teams 这样
|
||||
|
||||
## 决策
|
||||
|
||||
启动器在 `OPTIONAL_BUNDLES`(`packages/boot/app-boot/src/profile.ts`,与 profile 模板并列)里点名安装随附、供用户开启的组合包。每一个都必须是 `apps/cli` 声明了 `dsh.bundle.patch` 的运行时依赖,且不被任何随附 profile 模板选中。插件管理器的 `listBundles` 把这类组合包报告为 `optional`:选中前保持关闭、永不可卸载、像其他安装提供的组合包一样从安装目录解析。Web 插件页以可选组合包开启「官方」分组,属于实验包的带实验性标签,排在 profile 自己已安装的组合包之前。
|
||||
启动器在 `OPTIONAL_BUNDLES`(`packages/boot/app-boot/src/profile.ts`,与 profile 模板并列)里点名安装随附、供用户开启的组合包。每一个都必须是 `apps/cli` 声明了 `dsh.bundle.patch` 的运行时依赖,且不被任何随附 profile 模板选中。插件管理器的 `listBundles` 把这类组合包报告为 `optional`:选中前保持关闭、永不可卸载、像其他安装提供的组合包一样从安装目录解析。Web 插件页在「官方」分组展示可供选择的可选组合包,属于实验包的带实验性标签,排在 profile 自己已安装的组合包之前。[持久终端组合包](../../../../packages/experimental/terminal-bundle/README.zh.md)仍可供 Host 使用,但即使已启用也不提供页面开关;已有的 profile 选择保持不变。
|
||||
|
||||
默认产品隔离的规则保持不变,只声明一个例外:可选组合包的依赖图在默认产品之外。静态门禁跳过从 `@deepseek-ai/dsh` 到列表中组合包的 `dependencies` 边,仍然拒绝运行时 import、随附组合、preset 或默认模板对它的引用,拒绝列表没有点名的实验依赖,也拒绝不是运行时依赖或不是组合包的列表项。workspace 约束检查接受同样的 `dependencies` 边而不接受其他运行时依赖段;发布时的 packed-install 检查对已安装入口包跳过这些边,并要求列表中的每个组合包都已安装。
|
||||
|
||||
|
||||
@@ -112,7 +112,8 @@ describe('web e2e: plugin configuration pages', () => {
|
||||
await panel.getByRole('heading', { name: '实验性插件', exact: true, level: 1 }).waitFor()
|
||||
const bundles = await scaffold.ctx.pluginManager.listBundles()
|
||||
expect(await panel.locator('[data-plugin-group="more"] [data-plugin-package]').count())
|
||||
.toBe(bundles.filter(bundle => bundle.official && (bundle.listedByDefault !== false || bundle.enabled || bundle.installed)).length)
|
||||
.toBe(bundles.filter(bundle => bundle.name !== '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
&& bundle.official && (bundle.listedByDefault !== false || bundle.enabled || bundle.installed)).length)
|
||||
expect(await basic.count()).toBe(0)
|
||||
expect(await extensions.count()).toBe(0)
|
||||
expect(await panel.locator('[data-plugin-group="bundles"]').count()).toBe(0)
|
||||
|
||||
@@ -665,8 +665,11 @@ describe('web e2e: plugin manager', () => {
|
||||
await panel.getByRole('button', { name: '更多', exact: true }).click()
|
||||
await panel.getByRole('heading', { name: '实验性插件', exact: true, level: 1 }).waitFor()
|
||||
const bundles = await scaffold.ctx.pluginManager.listBundles()
|
||||
expect(bundles.some(bundle => bundle.name === '@deepseek-ai/dsh-experimental-terminal-bundle')).toBe(true)
|
||||
expect(await panel.getByRole('switch', { name: '启用 持久终端', exact: true }).count()).toBe(0)
|
||||
expect(await panel.locator('[data-plugin-group="more"] [data-plugin-package]').count())
|
||||
.toBe(bundles.filter(bundle => bundle.official && (bundle.listedByDefault !== false || bundle.enabled || bundle.installed)).length)
|
||||
.toBe(bundles.filter(bundle => bundle.name !== '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
&& bundle.official && (bundle.listedByDefault !== false || bundle.enabled || bundle.installed)).length)
|
||||
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 })
|
||||
@@ -684,7 +687,6 @@ describe('web e2e: plugin manager', () => {
|
||||
['@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-terminal-bundle', 1],
|
||||
['@deepseek-ai/dsh-experimental-session-titles-bundle', 1],
|
||||
['@deepseek-ai/dsh-experimental-badge-skill-bundle', 1],
|
||||
['@deepseek-ai/dsh-experimental-plugin-market-bundle', 1],
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading
|
||||
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.md
|
||||
/:
|
||||
en: 2b63472f97a928a2
|
||||
zh: 1db21d2ab8ee528a
|
||||
/manage-persistent-terminals-through-profile-configuration:
|
||||
en: 39659f2e595dbb93
|
||||
zh: 45b58c9ac1d0b006
|
||||
/manage-persistent-terminals-through-profile-configuration/change:
|
||||
en: bdbdd9596d9f45ed
|
||||
zh: e874ef3b122cea38
|
||||
/manage-persistent-terminals-through-profile-configuration/migration:
|
||||
en: 87bdea56366ec097
|
||||
zh: ed6add607169b1ba
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
kind: upgrade-guide
|
||||
description: "Persistent-terminal bundle controls leave the Plugins page; profile configuration still enables and disables the bundle."
|
||||
---
|
||||
|
||||
# Manage persistent terminals through profile configuration
|
||||
|
||||
English | [中文](guide.zh.md)
|
||||
|
||||
## Change
|
||||
|
||||
Web and Desktop no longer show the persistent-terminal bundle in Plugins lists or detail pages, including for profiles that already enabled it. The package and existing activation remain intact. The minimal preset's own persistent shell is independent of this bundle.
|
||||
|
||||
## Migration
|
||||
|
||||
1. To keep an existing selection, no action is required. To change it, open `$DSH_HOME/profiles/<name>/package.json`, where the default home is `~/.dsh` and `<name>` is the running profile, such as `web` or `desktop`.
|
||||
2. Remove `@deepseek-ai/dsh-experimental-terminal-bundle` from `dsh.profile.bundles` to disable it, or add it to enable it. Keep the other entries and dependencies intact.
|
||||
3. Restart the same profile to apply the selection. For a CLI-managed profile, run `dsh --profile <name> --dump-config`: the `optional-persistent-terminals` group is present only when the bundle is selected. See the [profile reference](../../../../apps/cli/reference/README.md#profile-boot).
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
kind: upgrade-guide
|
||||
description: "持久终端组合包开关移出插件页,仍可通过 profile 配置启用或关闭组合包。"
|
||||
---
|
||||
|
||||
# 通过 profile 配置管理持久终端
|
||||
|
||||
[English](guide.md) | 中文
|
||||
|
||||
## 变更
|
||||
|
||||
Web 和 Desktop 的插件列表和详情页不再显示持久终端组合包,包括此前已启用它的 profile。包及已有启用状态保持不变。minimal 预设自带的持久 shell 独立于此组合包。
|
||||
|
||||
## 迁移
|
||||
|
||||
1. 保留已有选择无需操作。如需更改,打开 `$DSH_HOME/profiles/<name>/package.json`,home 默认为 `~/.dsh`,`<name>` 是运行中的 profile,例如 `web` 或 `desktop`。
|
||||
2. 从 `dsh.profile.bundles` 中移除 `@deepseek-ai/dsh-experimental-terminal-bundle` 即可关闭,加入即可启用。保留其他条目和依赖。
|
||||
3. 重启同一个 profile 后生效。对于 CLI 管理的 profile,运行 `dsh --profile <name> --dump-config`:只有选中此组合包时,配置才包含 `optional-persistent-terminals` 分组。详见 [profile 参考](../../../../apps/cli/reference/README.zh.md#profile-boot)。
|
||||
@@ -216,7 +216,8 @@ export const DEFAULT_PROFILE_BUNDLES: readonly string[] = ['@deepseek-ai/dsh-bas
|
||||
* The bundles the dsh installation ships for a person to switch on: each a
|
||||
* runtime dependency of the installation that declares `dsh.bundle.patch`,
|
||||
* an `icon`, and `./locale/*.json` display metadata, selected by no shipped
|
||||
* template, and offered switched off by the plugin manager
|
||||
* template, and offered switched off by the plugin manager except persistent
|
||||
* terminals, which have no page switch
|
||||
* ([rationale](../../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md),
|
||||
* [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)).
|
||||
*/
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
en: 9312d8b1b381378f
|
||||
zh: 8d0ae7ad26ada2ac
|
||||
/deepseek-ai-dsh-client-ui-plugin-manager/use-this-package/switching-a-bundle:
|
||||
en: 58a4ec22fa624531
|
||||
zh: f838445232446850
|
||||
en: 390dc85aceac033a
|
||||
zh: 746ceae45f70dd33
|
||||
/deepseek-ai-dsh-client-ui-plugin-manager/use-this-package/switching-one-row-of-a-bundle:
|
||||
en: d3627d4dba5e6cc2
|
||||
zh: e0d0eada4c20331f
|
||||
|
||||
@@ -74,7 +74,7 @@ After the checks, the list toolbar says how many plugins can be updated, that al
|
||||
|
||||
### Switching a bundle
|
||||
|
||||
A bundle's page shows its full package name under the title. Its **Source** section, after the rows, names the spec that installs it elsewhere, as `pnpm add` accepts it, or **Built in** for an official bundle the installation ships, then its current version. A bundle's switch changes its layer selection. A displayed detail document stays visible while a profile change triggers a fresh read; the result replaces it when ready. While the Host applies the change, the switch stays disabled and a spinner appears beside it; the action area permanently reserves 22px to the left of the switch. A persistent status region announces the pending change to screen readers. A profile with HMR recomposes before the operation completes; one without HMR, and a bundle a higher layer overrides, say so in a toast. A bundle the Host cannot read carries a problem tag and its reason on its page and cannot be switched on; one that provides the management components stays locked. The Host answers with error codes, which the page's dictionary words; pnpm's and the Loader's own diagnostics are shown as they are. The page excludes built-in profile bundles from cards even when the profile holds them as dependencies or the Host reports an error. The Host inventory remains complete; the Settings Plugins section's Plugin list tab inspects their plugins.
|
||||
A bundle's page shows its full package name under the title. Its **Source** section, after the rows, names the spec that installs it elsewhere, as `pnpm add` accepts it, or **Built in** for an official bundle the installation ships, then its current version. A bundle's switch changes its layer selection. A displayed detail document stays visible while a profile change triggers a fresh read; the result replaces it when ready. While the Host applies the change, the switch stays disabled and a spinner appears beside it; the action area permanently reserves 22px to the left of the switch. A persistent status region announces the pending change to screen readers. A profile with HMR recomposes before the operation completes; one without HMR, and a bundle a higher layer overrides, say so in a toast. A bundle the Host cannot read carries a problem tag and its reason on its page and cannot be switched on; one that provides the management components stays locked. The Host answers with error codes, which the page's dictionary words; pnpm's and the Loader's own diagnostics are shown as they are. The page excludes built-in profile bundles and the persistent-terminal bundle from cards and detail pages, regardless of activation, dependency declarations, or Host errors. Hiding a bundle preserves its Host availability and activation. The Host inventory remains complete; the Settings Plugins section's Plugin list tab inspects their plugins.
|
||||
|
||||
### Switching one row of a bundle
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ Host 将网络失败或超时归因于 GitHub 地址,且提供 npmmirror 时
|
||||
|
||||
### 切换一个组合包
|
||||
|
||||
组合包页面在标题下方显示完整包名。组件列表之后的「来源信息」给出在别处安装它所需的 spec(`pnpm add` 接受的形式),安装随附的官方组合包显示「内置」,随后是当前版本。组合包开关改变其层选择。profile 变更触发重新读取时,已显示的详情文档保持可见,直到新结果返回。Host 应用更改期间,开关保持禁用,旁边显示旋转指示器;操作区在开关左侧固定预留 22px。常驻状态区域向屏幕阅读器播报进行中的更改。启用了 HMR 的 profile 在操作完成前重组;没有 HMR 的 profile,以及被更高层覆盖的组合包,会以 toast 说明。Host 读不了的组合包带异常标签,其页面给出原因,且不能打开;提供管理组件的组合包保持锁定。Host 以错误码作答,由页面字典措辞;pnpm 与 Loader 自己的诊断原样显示。页面从卡片中排除内置 profile 组合包,即使 profile 将它们列为依赖或 Host 报告了异常。Host 清单仍保留完整数据;设置中「插件」分区的「插件列表」标签页负责查看它们的插件。
|
||||
组合包页面在标题下方显示完整包名。组件列表之后的「来源信息」给出在别处安装它所需的 spec(`pnpm add` 接受的形式),安装随附的官方组合包显示「内置」,随后是当前版本。组合包开关改变其层选择。profile 变更触发重新读取时,已显示的详情文档保持可见,直到新结果返回。Host 应用更改期间,开关保持禁用,旁边显示旋转指示器;操作区在开关左侧固定预留 22px。常驻状态区域向屏幕阅读器播报进行中的更改。启用了 HMR 的 profile 在操作完成前重组;没有 HMR 的 profile,以及被更高层覆盖的组合包,会以 toast 说明。Host 读不了的组合包带异常标签,其页面给出原因,且不能打开;提供管理组件的组合包保持锁定。Host 以错误码作答,由页面字典措辞;pnpm 与 Loader 自己的诊断原样显示。页面从卡片和详情页中排除内置 profile 组合包和持久终端组合包,无论其启用状态、依赖声明或 Host 异常如何。隐藏组合包保留其在 Host 中的可用性和启用状态。Host 清单仍保留完整数据;设置中「插件」分区的「插件列表」标签页负责查看它们的插件。
|
||||
|
||||
### 切换组合包里的一行
|
||||
|
||||
|
||||
@@ -95,14 +95,18 @@ function AddPluginMenu({ t, disabled, openInstall, renderSlot }: {
|
||||
/** How long the list marks a package an install just enabled. */
|
||||
const HIGHLIGHT_MS = 2_400
|
||||
|
||||
/** Built-in profile bundles stay out of this page even when the profile declares them as dependencies. */
|
||||
const BUILTIN_PROFILE_BUNDLES = new Set([
|
||||
/**
|
||||
* Built-in profile bundles and persistent terminals have no management page.
|
||||
* Their Host availability and activation stay intact.
|
||||
*/
|
||||
const HIDDEN_BUNDLES = new Set([
|
||||
'@deepseek-ai/dsh-base',
|
||||
'@deepseek-ai/dsh-web-app',
|
||||
'@deepseek-ai/dsh-headless',
|
||||
'@deepseek-ai/dsh-sdk-app',
|
||||
'@deepseek-ai/dsh-acp-app',
|
||||
'@deepseek-ai/dsh-sdk-minimal',
|
||||
'@deepseek-ai/dsh-experimental-terminal-bundle',
|
||||
])
|
||||
|
||||
/** The optional bundles the main list always holds, in this order; new bundles join the main list. */
|
||||
@@ -117,7 +121,6 @@ const MORE_BUNDLES = [
|
||||
'@deepseek-ai/dsh-cua-bundle',
|
||||
'@deepseek-ai/dsh-experimental-tool-worktree',
|
||||
'@deepseek-ai/dsh-experimental-cot-translation-bundle',
|
||||
'@deepseek-ai/dsh-experimental-terminal-bundle',
|
||||
'@deepseek-ai/dsh-experimental-session-search',
|
||||
'@deepseek-ai/dsh-experimental-session-titles-bundle',
|
||||
'@deepseek-ai/dsh-experimental-badge-skill-bundle',
|
||||
@@ -1560,10 +1563,9 @@ export function PluginManagerPage(props: PluginManagerPageProps): ReactNode {
|
||||
}, [highlight, clearHighlight])
|
||||
const noticeLine = state.notice === null || state.notice.kind === 'refresh-failed' ? null : noticeText(state.notice, t)
|
||||
|
||||
// The page manages what the person installed, what the installation ships for them to switch on, and a
|
||||
// selected name the Host cannot read; the installation's other bundles are inspected in the Settings
|
||||
// Plugins section's Plugin list tab.
|
||||
const listed = state.packages.filter(pkg => !BUILTIN_PROFILE_BUNDLES.has(pkg.name)
|
||||
// The page omits profile bundles and persistent terminals. Other installed or offered bundles and
|
||||
// unreadable selections remain manageable; Settings' Plugin list inspects the full Host inventory.
|
||||
const listed = state.packages.filter(pkg => !HIDDEN_BUNDLES.has(pkg.name)
|
||||
&& (pkg.listedByDefault !== false || pkg.enabled || pkg.installed)
|
||||
&& (pkg.installed || pkg.official || pkg.error !== undefined))
|
||||
const mine = listed.filter(pkg => !pkg.official)
|
||||
|
||||
@@ -117,7 +117,6 @@ const EXPERIMENTAL_BUNDLES: readonly string[] = [
|
||||
'@deepseek-ai/dsh-experimental-inspector-profile',
|
||||
'@deepseek-ai/dsh-experimental-tool-worktree',
|
||||
'@deepseek-ai/dsh-experimental-cot-translation-bundle',
|
||||
'@deepseek-ai/dsh-experimental-terminal-bundle',
|
||||
'@deepseek-ai/dsh-experimental-session-search',
|
||||
'@deepseek-ai/dsh-experimental-session-titles-bundle',
|
||||
'@deepseek-ai/dsh-experimental-badge-skill-bundle',
|
||||
|
||||
@@ -740,7 +740,7 @@ describe('PluginManagerPage', () => {
|
||||
expect(locked.getAttribute('title')).toBe(en.reasonManagementRequired)
|
||||
})
|
||||
|
||||
it('omits built-in profile dependencies while retaining optional and third-party bundles', () => {
|
||||
it('omits profile and persistent-terminal bundles while retaining other optional and third-party bundles', () => {
|
||||
renderTab({
|
||||
packages: [
|
||||
...[
|
||||
@@ -750,6 +750,7 @@ describe('PluginManagerPage', () => {
|
||||
'@deepseek-ai/dsh-sdk-app',
|
||||
'@deepseek-ai/dsh-acp-app',
|
||||
'@deepseek-ai/dsh-sdk-minimal',
|
||||
'@deepseek-ai/dsh-experimental-terminal-bundle',
|
||||
].map(name => pkg({ name })),
|
||||
pkg({ name: '@acme/dsh-base', readOnlyReason: 'management-required' }),
|
||||
pkg({ name: 'dsh-better-sidebar' }),
|
||||
@@ -762,9 +763,29 @@ describe('PluginManagerPage', () => {
|
||||
expect(document.querySelector('[data-plugin-count]')).toBeNull()
|
||||
})
|
||||
|
||||
it.each([false, true])('shows an empty list for built-in bundles with errors and installed=%s', (installed) => {
|
||||
it.each([false, true])('hides persistent terminals from both lists and direct navigation without changing enabled=%s', (enabled) => {
|
||||
const name = '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
const b = renderTab({ packages: [
|
||||
pkg({ name, official: true, enabled, rows: [row()] }),
|
||||
pkg({ name: '@deepseek-ai/dsh-experimental-agent-team-profile', official: true }),
|
||||
] })
|
||||
expect(document.querySelector(`[data-plugin-package="${name}"]`)).toBeNull()
|
||||
fireEvent.click(screen.getByRole('button', { name: en.moreAction }))
|
||||
expect(screen.getByRole('heading', { name: en.moreTitle, level: 1 })).toBeTruthy()
|
||||
expect(document.querySelector(`[data-plugin-package="${name}"]`)).toBeNull()
|
||||
act(() => { b.navigation.actions.setView({ kind: 'package', name }) })
|
||||
expect(document.querySelector('[data-plugin-detail]')).toBeNull()
|
||||
act(() => { b.navigation.actions.setView({ kind: 'row', name, rowId: 'sidebar' }) })
|
||||
expect(document.querySelector('[data-plugin-row-detail]')).toBeNull()
|
||||
expect(screen.queryByRole('switch', { name: en.enableToggle.replace('{name}', name) })).toBeNull()
|
||||
expect(b.actions.setEnabled).not.toHaveBeenCalled()
|
||||
expect(b.actions.setRowEnabled).not.toHaveBeenCalled()
|
||||
expect(b.actions.uninstall).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it.each([false, true])('shows an empty list for hidden bundles with errors and installed=%s', (installed) => {
|
||||
renderTab({
|
||||
packages: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'].map(name => pkg({
|
||||
packages: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app', '@deepseek-ai/dsh-experimental-terminal-bundle'].map(name => pkg({
|
||||
name, installed, error: { code: 'operation-error', diagnostic: 'Unreadable bundle' },
|
||||
})),
|
||||
})
|
||||
@@ -1143,7 +1164,7 @@ describe('PluginManagerPage', () => {
|
||||
'@acme/shipped-exploration',
|
||||
])('omits %s from default lists while retaining explicit profile selections and installations', (name) => {
|
||||
const entry = pkg({ name, installed: false, optional: true, removable: false, enabled: false, listedByDefault: false })
|
||||
const other = pkg({ name: '@deepseek-ai/dsh-experimental-terminal-bundle', installed: false, optional: true, enabled: false })
|
||||
const other = pkg({ name: '@deepseek-ai/dsh-experimental-session-titles-bundle', installed: false, optional: true, enabled: false })
|
||||
const { actions, navigation, set, setLanguage } = renderTab({ packages: [other, entry] })
|
||||
const card = () => document.querySelector(`[data-plugin-package="${name}"]`)
|
||||
for (const dict of [en, zh]) {
|
||||
@@ -1197,7 +1218,7 @@ describe('PluginManagerPage', () => {
|
||||
})
|
||||
|
||||
it('returns from package details to the secondary page and retains it across React remounts', () => {
|
||||
const name = '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
const name = '@deepseek-ai/dsh-experimental-session-titles-bundle'
|
||||
const b = renderTab({ packages: [pkg({ name, official: true, enabled: false })] })
|
||||
fireEvent.click(screen.getByRole('button', { name: en.moreAction }))
|
||||
expect(screen.getByRole('heading', { name: en.moreTitle, level: 1 })).toBeTruthy()
|
||||
@@ -1240,7 +1261,7 @@ describe('PluginManagerPage', () => {
|
||||
})
|
||||
|
||||
it('returns a held-back bundle opened outside the lists to the list that shows it', () => {
|
||||
const name = '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
const name = '@deepseek-ai/dsh-experimental-session-titles-bundle'
|
||||
const b = renderTab({ packages: [pkg({ name, official: true, enabled: false })] })
|
||||
act(() => { b.navigation.actions.setView({ kind: 'package', name }) })
|
||||
expect(document.querySelector(`[data-plugin-detail="${name}"]`)).toBeTruthy()
|
||||
@@ -2204,7 +2225,7 @@ describe('PluginManagerPage', () => {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollIntoView')
|
||||
Object.defineProperty(Element.prototype, 'scrollIntoView', { value: scrollIntoView, configurable: true })
|
||||
try {
|
||||
const { actions, set } = renderTab({ packages: [pkg(), pkg({ name: '@deepseek-ai/dsh-experimental-terminal-bundle', official: true })] })
|
||||
const { actions, set } = renderTab({ packages: [pkg(), pkg({ name: '@deepseek-ai/dsh-experimental-session-titles-bundle', official: true })] })
|
||||
// A package the list does not show has nothing to scroll to; the mark still times out.
|
||||
set({ highlight: 'missing' })
|
||||
expect(scrollIntoView).not.toHaveBeenCalled()
|
||||
@@ -2227,7 +2248,7 @@ describe('PluginManagerPage', () => {
|
||||
|
||||
it('highlights only the visible list and does not extend the mark when navigating or refreshing', () => {
|
||||
vi.useFakeTimers()
|
||||
const name = '@deepseek-ai/dsh-experimental-terminal-bundle'
|
||||
const name = '@deepseek-ai/dsh-experimental-session-titles-bundle'
|
||||
const scrollIntoView = vi.fn()
|
||||
const descriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollIntoView')
|
||||
Object.defineProperty(Element.prototype, 'scrollIntoView', { value: scrollIntoView, configurable: true })
|
||||
@@ -2418,7 +2439,7 @@ it.each([false, true])('shows progress only for the changing bundle and clears i
|
||||
})
|
||||
|
||||
it.each([false, true])('opens activation guidance details and returns to the originating list (experimental: %s)', (fromMore) => {
|
||||
const name = fromMore ? '@deepseek-ai/dsh-experimental-terminal-bundle' : 'dsh-better-sidebar'
|
||||
const name = fromMore ? '@deepseek-ai/dsh-experimental-session-titles-bundle' : 'dsh-better-sidebar'
|
||||
const bundle = pkg({ name, official: fromMore })
|
||||
const { set, actions } = renderTab({ packages: [{ ...bundle, enabled: false }] }, { bundles: new Set([name]) }, {
|
||||
[`plugins.bundle.activation:${name}`]: (_view, owner) => <button onClick={(owner as PluginActivationOwnerProps).onOpenDetails}>Go to setup</button>,
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
en: cc18693529aee09c
|
||||
zh: fbf1c7d8388eeba8
|
||||
/deepseek-ai-dsh-experimental-terminal-bundle/summary:
|
||||
en: 161ff8d60aa7623e
|
||||
zh: 90ea4ac87b96f20a
|
||||
en: 50f2c8029ae3233d
|
||||
zh: 00db7cd933a08ef8
|
||||
/deepseek-ai-dsh-experimental-terminal-bundle/table-of-contents:
|
||||
en: d152484eb41ac6b4
|
||||
zh: 988e839059414d27
|
||||
/deepseek-ai-dsh-experimental-terminal-bundle/use-this-package:
|
||||
en: 924d2c0de1f247a7
|
||||
zh: 7d77aef5ceb3f097
|
||||
en: 8b2d9dd5727d0a27
|
||||
zh: ca6c9b8e3d196a54
|
||||
/deepseek-ai-dsh-experimental-terminal-bundle/understand-the-implementation:
|
||||
en: 0da35df3f93e3b7f
|
||||
zh: 481b786e161616ab
|
||||
|
||||
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
||||
|
||||
## Summary
|
||||
|
||||
Add six experimental global terminal tools to every Agent. The bundle owns an isolated terminal registry with the platform shell backend; terminals remain Agent-owned. It ships switched off in Web and Desktop. Select it in Plugins to enable it.
|
||||
Add six experimental global terminal tools to every Agent. The bundle owns an isolated terminal registry with the platform shell backend; terminals remain Agent-owned. It ships switched off in Web and Desktop and is omitted from the Plugins bundle lists and detail pages.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -25,9 +25,9 @@ Add six experimental global terminal tools to every Agent. The bundle owns an is
|
||||
<a id="use-this-package"></a>
|
||||
## Use this package
|
||||
|
||||
In Web or Desktop, open Plugins and enable **Persistent terminals** in Official. Switch it off to remove its profile layer.
|
||||
In `$DSH_HOME/profiles/<name>/package.json` (default home: `~/.dsh`), add `@deepseek-ai/dsh-experimental-terminal-bundle` to `dsh.profile.bundles` to enable its profile layer; remove it from that list to disable it. Restart that profile to apply the change; see the [profile reference](../../../apps/cli/reference/README.md#profile-boot). The [minimal preset](../../bundle/web-app/presets/minimal.patch.yml) loads its own persistent shell independently of this bundle.
|
||||
|
||||
Enabling or disabling the bundle registers or removes its global tools in the running Host, so every Agent sees the change on its next request, in every preset including minimal.
|
||||
The selected layer adds its global tools to every Agent in the Host, in every preset including minimal. Hiding the management entry preserves existing selections; the [upgrade guide](../../../docs/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.md) explains how to disable a previously enabled layer.
|
||||
|
||||
-----
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ kind: "package-bundle"
|
||||
|
||||
## 概述
|
||||
|
||||
为所有智能体添加六个实验性全局终端工具。组合包拥有隔离的终端注册表和平台 shell 后端;终端仍由智能体拥有。 Web 和 Desktop 随附此功能,默认关闭。在插件页选择它即可启用。
|
||||
为所有智能体添加六个实验性全局终端工具。组合包拥有隔离的终端注册表和平台 shell 后端;终端仍由智能体拥有。 Web 和 Desktop 随附此功能,默认关闭,且不在插件页的组合包列表和详情页显示。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -25,9 +25,9 @@ kind: "package-bundle"
|
||||
<a id="use-this-package"></a>
|
||||
## 使用此包
|
||||
|
||||
在 Web 或 Desktop 中打开插件页,在官方分组启用 **持久终端**。关闭后移除其配置层。
|
||||
在 `$DSH_HOME/profiles/<name>/package.json` 中(home 默认为 `~/.dsh`),将 `@deepseek-ai/dsh-experimental-terminal-bundle` 加入 `dsh.profile.bundles` 即可启用其配置层;从列表移除即可关闭。重启该 profile 后生效,详见 [profile 参考](../../../apps/cli/reference/README.zh.md#profile-boot)。[minimal 预设](../../bundle/web-app/presets/minimal.patch.yml) 独立加载自己的持久 shell,不依赖此组合包。
|
||||
|
||||
启用或关闭组合包会在运行中的 Host 注册或移除其全局工具,因此所有预设(包括 minimal)中的每个智能体都会在下一次请求时看到变化。
|
||||
选中的配置层为 Host 中的每个智能体添加全局工具,覆盖所有预设(包括 minimal)。隐藏管理入口保留已有的启用配置;[升级说明](../../../docs/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.zh.md)介绍如何关闭此前启用的配置层。
|
||||
|
||||
-----
|
||||
|
||||
|
||||
Reference in new issue
Block a user