From e01ad81fdf42fab301818a16499b8fece5bc0417 Mon Sep 17 00:00:00 2001 From: Cloga Chen Date: Sun, 25 Oct 2026 11:19:12 +0800 Subject: [PATCH 1/3] fix(client): clarify version-neutral Desktop lifecycle guidance Refs #371. Keep historical rc.2 evidence separate from current guidance and defer restart decisions to the native manager. Assisted-by: GitHub Copilot App Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 2 +- README.zh.md | 2 +- docs/web-lifecycle-rc2.md | 8 ++++++ src/web-search-routing-card.ts | 4 +-- tests/scripts/web-lifecycle-copy.test.mjs | 32 +++++++++++++++++++++++ tests/web-search-routing-card.spec.ts | 15 ++++++++--- 6 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tests/scripts/web-lifecycle-copy.test.mjs diff --git a/README.md b/README.md index a341a141..3edbe187 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ Saved account names can load without activating the account. Names are cached fo Account-management metadata and identity reads have a fifteen-second Client deadline instead of indefinite Checking. An initial read failure offers metadata-only **Retry**; late results are ignored. This does not cancel Host work, retry automatically or unlock an unresolved account mutation. -**Desktop lifecycle:** the current rc.3 public-Loader fixture preserves active Web consumers on a single-step add, but staged add and remove/re-add can leave the global `web` service unavailable and dependent account integration inactive. No feature-equivalent plugin-only recovery API is currently available; [issue #371](https://github.com/cloga/dsh-github-copilot/issues/371) remains open. An in-place upgrade without native HMR is explicitly `restart-required`; honor that manager result. The synthetic fixture does not justify repeated toggles or a restart when the manager has not requested one. See the [rc.3 lifecycle evidence](./docs/web-lifecycle-rc2.md). +**Desktop lifecycle:** the current rc.3 public-Loader fixture preserves active Web consumers on a single-step add, but staged add and remove/re-add can leave the global `web` service unavailable and dependent account integration inactive. No feature-equivalent plugin-only recovery API is currently available; [issue #371](https://github.com/cloga/dsh-github-copilot/issues/371) remains open. An in-place upgrade without native HMR is explicitly `restart-required`; honor that manager result. The synthetic fixture does not justify repeated toggles or a restart when the manager has not requested one. The card's **Desktop plugin lifecycle** note is general guidance, not detection of your Desktop version or a restart requirement. See [Desktop guidance and version-scoped lifecycle evidence](./docs/web-lifecycle-rc2.md#desktop-guidance); the rc.2 filename is retained for link stability, not current-host identification. ## Auto and model preferences diff --git a/README.zh.md b/README.zh.md index 9990193b..00447032 100644 --- a/README.zh.md +++ b/README.zh.md @@ -162,7 +162,7 @@ Desktop 原生包管理器和已核验的随附 CLI 都有 profile 边界。 账号管理的元数据和身份读取使用 15 秒 Client 展示期限,避免无限 Checking。首次读取失败提供只读元数据**重试**;迟到结果不会覆盖新状态。不取消 Host 工作、不自动重试,也不会解锁尚未完成的账号修改操作。 -**Desktop 生命周期:**当前 rc.3 公共 Loader 测试中,单步添加可保留正在使用的 Web 消费者;但分阶段添加或移除后重新添加,可能导致全局 `web` 服务不可用及依赖它的账号集成无法启动。目前没有功能等价的插件侧恢复 API;[#371](https://github.com/cloga/dsh-github-copilot/issues/371) 仍保持开放。没有原生 HMR 时,原生管理器会明确返回 `restart-required`;应遵循该结果。合成测试本身不构成反复切换或重启的依据。参见 [rc.3 生命周期证据](./docs/web-lifecycle-rc2.md)。 +**Desktop 生命周期:**当前 rc.3 公共 Loader 测试中,单步添加可保留正在使用的 Web 消费者;但分阶段添加或移除后重新添加,可能导致全局 `web` 服务不可用及依赖它的账号集成无法启动。目前没有功能等价的插件侧恢复 API;[#371](https://github.com/cloga/dsh-github-copilot/issues/371) 仍保持开放。没有原生 HMR 时,原生管理器会明确返回 `restart-required`;应遵循该结果。合成测试本身不构成反复切换或重启的依据。卡片中的 **Desktop 插件生命周期**仅为通用指导,不检测当前 Desktop 版本或是否需要重启。参见 [Desktop 指导与按版本区分的生命周期证据](./docs/web-lifecycle-rc2.md#desktop-guidance);保留 rc.2 文件名是为了链接稳定,不代表当前宿主版本。 ## Auto 与模型偏好 diff --git a/docs/web-lifecycle-rc2.md b/docs/web-lifecycle-rc2.md index 7058698a..b2b2ff54 100644 --- a/docs/web-lifecycle-rc2.md +++ b/docs/web-lifecycle-rc2.md @@ -2,6 +2,14 @@ This keeps the existing rc.2 documentation path for link stability, but updates its contents to the repository's current supported Core, DSH `0.2.1-rc.3`. It exercises the exact published Loader/Web packages and plugin bundle through public APIs. The synthetic fixture makes no network calls and removes its temporary files and Loader fibers. It does not exercise the native Desktop package manager or claim the observed account-status incident was caused by any one internal transition. Earlier rc.2 findings are historical; the rc.3 test results below are authoritative for the current plugin line. +## Desktop guidance + +The Web search card uses the version-neutral heading **Desktop plugin lifecycle**. This is general guidance: it does not detect the installed Desktop version or whether a restart is required. + +If the native plugin manager explicitly reports `restart-required` after a plugin change, fully exit Desktop (including its tray/background process) and launch it again. This is not a blanket instruction to restart after every disable, removal or upgrade, and it does not promise that a restart fixes every activation error. + +If the plugin is already **Off** and the manager shows only pending entries waiting for a service, do not repeatedly toggle it as a recovery attempt. The rc.2 disable observation below is historical context, not a diagnosis of the current host; the rc.3 synthetic transitions are separately scoped evidence. Other activation errors and mixed diagnostics require their own investigation. + ## Reproduce From the repository root, after the normal build: diff --git a/src/web-search-routing-card.ts b/src/web-search-routing-card.ts index 9fcec1e3..e82c3c0a 100644 --- a/src/web-search-routing-card.ts +++ b/src/web-search-routing-card.ts @@ -376,9 +376,9 @@ export function WebSearchRoutingCard(props: SearchRoutingCardProps): ReactElemen 'data-copilot-native-ui': true, 'aria-busy': loading || saving !== undefined }, createElement('style', null, nativeSettingsCss), createElement('div', { role: 'note', style: lifecycleNoticeStyle, 'data-dsh-web-search-lifecycle-notice': true }, - createElement('strong', { style: { fontWeight: 500 } }, 'Desktop 0.2.0-rc.2 lifecycle note / Desktop 0.2.0-rc.2 生命周期提示'), + createElement('strong', { style: { fontWeight: 500 } }, 'Desktop plugin lifecycle / Desktop 插件生命周期'), createElement('span', { style: { opacity: 0.85 } }, - 'After disabling, removing, or upgrading this plugin, fully exit and restart Desktop to complete Web service recomposition. If the native manager shows only pending entries waiting for a service and this plugin is Off, restart instead of toggling it repeatedly. / 停用、移除或升级本插件后,请完全退出并重新启动 Desktop,以完成 Web 服务重编排。若原生管理器仅显示等待某项服务的 pending 条目且本插件已为 Off,请直接重启,不要反复切换。'), + 'If the plugin manager reports restart-required after a plugin change, fully exit and restart Desktop. If this plugin is Off and the manager shows only pending entries waiting for a service, do not toggle it repeatedly. This note does not detect your Desktop version or a restart requirement. / 插件变更后,若插件管理器提示 restart-required,请完全退出并重新启动 Desktop。若本插件已为 Off 且管理器仅显示等待某项服务的 pending 条目,请勿反复切换。本提示不检测 Desktop 版本或是否需要重启。'), ), restartRequired ? createElement('div', { role: 'alert', style: restartBannerStyle, 'data-dsh-web-search-restart-banner': true }, createElement('strong', { style: { fontWeight: 500 } }, 'Restart required to complete update / 检测到更新,请重启 Desktop 完成生效'), diff --git a/tests/scripts/web-lifecycle-copy.test.mjs b/tests/scripts/web-lifecycle-copy.test.mjs new file mode 100644 index 00000000..920aaec9 --- /dev/null +++ b/tests/scripts/web-lifecycle-copy.test.mjs @@ -0,0 +1,32 @@ +import assert from 'node:assert/strict' +import { readFile } from 'node:fs/promises' +import { test } from 'node:test' + +const source = await readFile(new URL('../../src/web-search-routing-card.ts', import.meta.url), 'utf8') +const notice = source.slice(source.indexOf("createElement('div', { role: 'note', style: lifecycleNoticeStyle"), + source.indexOf("restartRequired ? createElement")) + +test('lifecycle notice is version-neutral, conditional guidance rather than runtime detection', () => { + assert.ok(notice.length > 0) + assert.match(notice, /Desktop plugin lifecycle \/ Desktop 插件生命周期/) + assert.match(notice, /If the plugin manager reports restart-required/) + assert.match(notice, /fully exit and restart Desktop/) + assert.match(notice, /do not toggle it repeatedly/) + assert.match(notice, /This note does not detect your Desktop version or a restart requirement/) + assert.match(notice, /若插件管理器提示 restart-required/) + assert.match(notice, /请完全退出并重新启动 Desktop/) + assert.match(notice, /本提示不检测 Desktop 版本或是否需要重启/) + assert.doesNotMatch(notice, /Desktop \d|After disabling, removing, or upgrading this plugin/) +}) + +test('README guidance links retain the stable evidence path and separate historical observations', async () => { + for (const name of ['README.md', 'README.zh.md']) { + const readme = await readFile(new URL(`../../${name}`, import.meta.url), 'utf8') + assert.match(readme, /\.\/docs\/web-lifecycle-rc2\.md#desktop-guidance/) + } + const evidence = await readFile(new URL('../../docs/web-lifecycle-rc2.md', import.meta.url), 'utf8') + assert.match(evidence, /## Desktop guidance/) + assert.match(evidence, /## Historical rc\.2 Desktop disable observation/) + assert.match(evidence, /does not detect the installed Desktop version/) + assert.match(evidence, /not a blanket instruction to restart after every disable, removal or upgrade/) +}) diff --git a/tests/web-search-routing-card.spec.ts b/tests/web-search-routing-card.spec.ts index fb746b93..642b9ecb 100644 --- a/tests/web-search-routing-card.spec.ts +++ b/tests/web-search-routing-card.spec.ts @@ -142,18 +142,25 @@ async function ready(remote = remotes()) { } describe('independent Web search Settings card', () => { - it('keeps rc.2 disable, removal, and upgrade restart guidance visible before mutation', async () => { + it('keeps version-neutral lifecycle guidance visible without claiming a detected restart requirement', async () => { const card = await ready() const tree = card.render() const notice = descendants(tree).find(node => node.props['data-dsh-web-search-lifecycle-notice'] === true) expect(notice?.props.role).toBe('note') - expect(text(notice)).toContain('After disabling, removing, or upgrading this plugin') + expect(text(notice)).toContain('Desktop plugin lifecycle / Desktop 插件生命周期') + expect(text(notice)).toContain('If the plugin manager reports restart-required') + expect(text(notice)).toContain('fully exit and restart Desktop') expect(text(notice)).toContain('only pending entries waiting for a service') expect(text(notice)).toContain('this plugin is Off') - expect(text(notice)).toContain('restart instead of toggling it repeatedly') - expect(text(notice)).toContain('停用、移除或升级本插件后') + expect(text(notice)).toContain('do not toggle it repeatedly') + expect(text(notice)).toContain('This note does not detect your Desktop version or a restart requirement') + expect(text(notice)).toContain('若插件管理器提示 restart-required') + expect(text(notice)).toContain('请完全退出并重新启动 Desktop') expect(text(notice)).toContain('等待某项服务的 pending 条目') expect(text(notice)).toContain('本插件已为 Off') + expect(text(notice)).toContain('本提示不检测 Desktop 版本或是否需要重启') + expect(text(notice)).not.toMatch(/0\.2\.[01]-rc\.[23]/) + expect(text(notice)).not.toContain('After disabling, removing, or upgrading this plugin') expect(text(notice)).not.toContain('service: web') expect(descendants(tree).some(node => node.props['data-dsh-web-search-restart-banner'])).toBe(false) }) From b86d874c1897e57e4d874f1db34ac540cc1bd5cb Mon Sep 17 00:00:00 2001 From: Cloga Chen Date: Sun, 25 Oct 2026 18:47:58 +0800 Subject: [PATCH 2/3] chore(release): prepare alpha.4 metadata for rc.3 Refs #453; preserve the rc.3 line and mark the candidate pending, not published. Assisted-by: GitHub Copilot App Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 10 +++++----- README.zh.md | 10 +++++----- deployment-baseline.json | 4 ++-- package.json | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1836fa95..2f9ac8de 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ GitHub Copilot account discovery, contextual Auto routing and hosted search for DSH. The plugin reuses DSH's published native adapter, retaining a profile-wide account default with independent Session next-turn choices; it does not patch Core or maintain a second model catalog. -**Historical stable release: [`0.4.1`](https://github.com/cloga/dsh-github-copilot/releases/tag/v0.4.1); pending DSH rc.3 update: `0.1.0-alpha.3.dsh.0.2.1.rc.3`.** DSH `0.2.1-rc.3` is a prerelease. This plugin line is a compatibility candidate, not a production Core upgrade recommendation; Desktop artifacts/signatures are unverified. Each exact DSH Core version starts an independent plugin sequence at `0.1.0-alpha.1.dsh.`; same-Core fixes increment `alpha.N`. The suffix normalizes Core `0.2.1-rc.3` to `dsh.0.2.1.rc.3`, but compatibility is validated against explicit metadata, not guessed from the name. Existing published versions/tags remain unchanged. Published, installed and loaded states remain separate. +**Historical stable release: [`0.4.1`](https://github.com/cloga/dsh-github-copilot/releases/tag/v0.4.1); prepared, unreleased DSH rc.3 metadata candidate: `0.1.0-alpha.4.dsh.0.2.1.rc.3`.** This PR prepares version metadata only; the alpha.4 GitHub Release and npm package have not been published. Do not use the alpha.4 install commands until both publication channels are verified. DSH `0.2.1-rc.3` is a prerelease. This plugin line is a compatibility candidate, not a production Core upgrade recommendation; Desktop artifacts/signatures are unverified. Each exact DSH Core version starts an independent plugin sequence at `0.1.0-alpha.1.dsh.`; same-Core fixes increment `alpha.N`. The suffix normalizes Core `0.2.1-rc.3` to `dsh.0.2.1.rc.3`, but compatibility is validated against explicit metadata, not guessed from the name. Existing published versions/tags remain unchanged. Published, installed and loaded states remain separate. Select by **exact Core**, never global SemVer maximum or npm `latest`/`alpha`. The read-only `node scripts/select-core-release.mjs 0.2.0-rc.2` command checks @@ -169,7 +169,7 @@ separately. For a **standalone named profile**: ```sh -dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.3.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.3.dsh.0.2.1.rc.3.tgz +dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.4.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.4.dsh.0.2.1.rc.3.tgz ``` The command above is a prepared-release example, usable only after publication and required CI qualification; it requires official DSH prerelease `0.2.1-rc.3`. **Do not install this candidate into production Desktop profiles.** Desktop artifacts/signatures and profile peer composition remain unverified; retain the existing compatible plugin on rc.2. The [historical rc.2 bundled-CLI qualification](./docs/npm-distribution.md#desktop-bundled-cli-on-official-rc2) does not qualify rc.3, and a generic/global `dsh` shim is not equivalent. No installation or restart is authorized. @@ -385,14 +385,14 @@ Commit attribution uses `Assisted-by` with the actual tool, never the model prov GitHub Releases and npm distribute the same original verified tarball. Pin a version; verify Release SHA-256 or npm `dist.integrity`. Never repack an immutable release or move/reuse its tag. ```sh -curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.3.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.3.dsh.0.2.1.rc.3.tgz -curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.3.dsh.0.2.1.rc.3/SHA256SUMS +curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.4.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.4.dsh.0.2.1.rc.3.tgz +curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.4.dsh.0.2.1.rc.3/SHA256SUMS sha256sum --check SHA256SUMS ``` ```powershell $expected = (Get-Content .\SHA256SUMS).Split()[0] -$actual = (Get-FileHash .\dsh-github-copilot-0.1.0-alpha.3.dsh.0.2.1.rc.3.tgz -Algorithm SHA256).Hash.ToLowerInvariant() +$actual = (Get-FileHash .\dsh-github-copilot-0.1.0-alpha.4.dsh.0.2.1.rc.3.tgz -Algorithm SHA256).Hash.ToLowerInvariant() if ($actual -cne $expected) { throw 'Release checksum mismatch' } ``` diff --git a/README.zh.md b/README.zh.md index 11ad276f..e9199d73 100644 --- a/README.zh.md +++ b/README.zh.md @@ -8,7 +8,7 @@ 为 DSH 提供 GitHub Copilot 账号模型发现、上下文 Auto 选模和 hosted search。插件复用 DSH 公开的原生适配器,保留 profile 全局默认账号,并支持 Session 后续 turn 指定独立账号;不修改 Core,也不维护第二套模型目录。 -**历史稳定版:[`0.4.1`](https://github.com/cloga/dsh-github-copilot/releases/tag/v0.4.1);DSH rc.3 更新候选:`0.1.0-alpha.3.dsh.0.2.1.rc.3`。** DSH `0.2.1-rc.3` 是预发布版本。本插件线是兼容性候选,不是生产 Core 升级建议;Desktop 制品/签名尚未核验。每个精确 DSH Core 版本都从独立插件序列 `0.1.0-alpha.1.dsh.` 开始;同一 Core 内修复递增 `alpha.N`。后缀将 Core `0.2.1-rc.3` 规范化为 `dsh.0.2.1.rc.3`,但兼容性仍须核对明确元数据,不能只猜版本名。既有已发布版本和 tag 不变。已发布、已安装、已加载仍是不同状态。 +**历史稳定版:[`0.4.1`](https://github.com/cloga/dsh-github-copilot/releases/tag/v0.4.1);已准备但未发布的 DSH rc.3 元数据候选:`0.1.0-alpha.4.dsh.0.2.1.rc.3`。** 本 PR 仅准备版本元数据;alpha.4 的 GitHub Release 和 npm 包尚未发布。两种发布渠道核验完成前,请勿使用 alpha.4 安装命令。DSH `0.2.1-rc.3` 是预发布版本。本插件线是兼容性候选,不是生产 Core 升级建议;Desktop 制品/签名尚未核验。每个精确 DSH Core 版本都从独立插件序列 `0.1.0-alpha.1.dsh.` 开始;同一 Core 内修复递增 `alpha.N`。后缀将 Core `0.2.1-rc.3` 规范化为 `dsh.0.2.1.rc.3`,但兼容性仍须核对明确元数据,不能只猜版本名。既有已发布版本和 tag 不变。已发布、已安装、已加载仍是不同状态。 按**精确 Core**选版本,不按全局 SemVer 最大值或 npm `latest`/`alpha`。 只读命令 `node scripts/select-core-release.mjs 0.2.0-rc.2` 先读取 @@ -141,7 +141,7 @@ node package/scripts/check-search-composition.mjs --profile-dir /absolute/profil **独立具名 profile**: ```sh -dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.3.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.3.dsh.0.2.1.rc.3.tgz +dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.1.0-alpha.4.dsh.0.2.1.rc.3/dsh-github-copilot-0.1.0-alpha.4.dsh.0.2.1.rc.3.tgz ``` 上面的命令是准备发布的示例,仅在发布且所需 CI 通过后可用;目标是官方 DSH 预发布版 `0.2.1-rc.3`。**不要把此候选安装到生产 Desktop profile。** Desktop 制品/签名及 profile peer 组合仍未核验;rc.2 应保留现有兼容插件。[历史 rc.2 随附 CLI 核验](./docs/npm-distribution.md#desktop-bundled-cli-on-official-rc2)不代表 rc.3 验收;全局/普通 `dsh` shim 不等价。本次不授权安装或重启。 @@ -352,14 +352,14 @@ Agent 从 `node scripts/agent.mjs describe --json`、`doctor --json`及`plan Date: Sun, 25 Oct 2026 18:55:59 +0800 Subject: [PATCH 3/3] docs(release): add prepared alpha.4 lifecycle notes Refs #453; satisfy the source-bound release-notes preflight without marking the candidate published. Assisted-by: GitHub Copilot App Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b212f61..344683c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.1.0-alpha.4.dsh.0.2.1.rc.3 (prepared) + +- Replace the stale rc.2 Desktop lifecycle heading with version-neutral guidance. Recommend a full exit and restart only when the native plugin manager reports `restart-required`; do not repeatedly toggle an Off plugin when the manager reports only pending service dependencies. +- Keep historical rc.2 Desktop observations distinct from current rc.3 synthetic Loader evidence, and synchronize the English/Chinese README and user-visible copy regressions (#453). +- Prepare same-Core alpha.4 metadata only. The rc.3 release mapping remains pending; no tag, GitHub Release, npm publication, profile installation or Desktop restart is included. + ## 0.1.0-alpha.3.dsh.0.2.1.rc.3 (prepared) - Explain projected-image admission failures through the standard native error path with bounded model, projected/allowed MIME, projected role/position and current build details (#426). Retain the existing fail-closed gate, explicit account restrictions and native projection ownership.