dsh-github-copilot 0.4.0-alpha.28 → 0.4.0-alpha.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -2
- package/CHANGELOG.md +8 -0
- package/README.md +13 -12
- package/README.zh.md +13 -12
- package/deployment-baseline.json +29 -1
- package/docs/session-search-routing.md +11 -5
- package/lib/client.js +120 -134
- package/lib/client.js.map +1 -1
- package/lib/index.js +69 -30
- package/lib/types/config.d.ts +1 -1
- package/lib/types/web-search-routing-card.d.ts +1 -2
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -87,14 +87,15 @@ Alpha.25 admits native `subagent/descriptor` v3, already v3 in the retained rc.1
|
|
|
87
87
|
- Copilot OAuth grant writes must rebuild only pi-ai's documented provider fields as a fresh plain JSON object; unrelated extension values never reach DSH credential storage.
|
|
88
88
|
- Settings changes are path-level. Never replace the whole `llm-pi-ai` section or unrelated provider profiles.
|
|
89
89
|
- Sign-out deletes only the Copilot credential record and keeps route settings.
|
|
90
|
-
- Hosted search serves either an eligible initiating `github-copilot` / managed `github-copilot-preview` route, or
|
|
90
|
+
- Hosted search serves either an eligible initiating `github-copilot` / managed `github-copilot-preview` route, or provider-owned independent search selected by the web-search router. Independent search preserves a nonempty explicit `searchModel` override; otherwise the Host considers at most three eligible Responses models from current account route facts, in deterministic ID order, without a static model list. Metadata alone is not search proof, and the final user query is sent once after candidate proof, never replayed across models. Both paths require an account-available model and supported search protocol; custom inline transport remains legacy-canonical only. Never substitute the global chat default or another Session's identity. The default `probe: true` path requires successful capability proof; `probe: false` is an explicit trust override, not an implicit fallback. Any request containing a file block, including one nested in tool-result content, must bypass the custom wire through `next()` so Core retains file projection ownership.
|
|
91
91
|
- Misconfiguration and API drift fail loudly with a named missing seam. Do not fall back to process-local secrets or implicit machine state.
|
|
92
92
|
- Host, Client, and Remote package entries must stay independently buildable and exported.
|
|
93
93
|
- The package must self-provide authorization when Core omits it, reuse an existing service without duplicate registration, and never activate the integration body before authorization is available.
|
|
94
94
|
|
|
95
95
|
## Session and migration ownership (V3, alpha.8, #99)
|
|
96
96
|
|
|
97
|
-
- One global Host account supplies many models; selected/history-backed Sessions retain independent model context. Auto-mode native search derives from the captured initiating Session's effective request-header/config or explicit `GenerateOptions`, never another Session or future global default C. Fixed/
|
|
97
|
+
- One global Host account supplies many models; selected/history-backed Sessions retain independent model context. Auto-mode native search derives from the captured initiating Session's effective request-header/config or explicit `GenerateOptions`, never another Session or future global default C. Fixed/fallback Copilot search uses the explicit provider-owned `searchModel` override when nonempty, otherwise bounded automatic account-owned Responses selection; it never borrows the Chat model, another Session's selection or the global chat default. `Agent.options` is the activation seed, not selected Session-model evidence; `installModelSelection` overrides request/assembly; Core records the effective `Session.requestHeader().config` before tools. Without proven request context, traditional search is unavailable. A newly selected pending model must not reuse the old request header as current prompt guidance. Per-owner plan caches prevent different-model A/B reuse/cancellation; metadata remains shared.
|
|
98
|
+
- The ordinary Web search card selects only the primary and fallback providers and saves both routing leaves in one namespace CAS. It must not depend on Copilot model discovery, a model selection or the Copilot settings namespace to save routing. Capture traced Settings/routing Remote faces once per UI registration so parent renders do not reset drafts. Preserve a legacy nonempty `searchModel` override; display it read-only and reset it only through an explicit, separate narrow CAS setting `searchModel: ''`, never as a routing-save side effect. Saving settings does not prove hosted-search capability.
|
|
98
99
|
- Cold Chat picker and `/model` `listModels()` ensure the shared managed source without Settings first. Actual cold managed search non-forcing ensures metadata before deriving facts; existing 24h maximum TTL, cooldown, credential, allowlist and capability/probe gates remain.
|
|
99
100
|
- Without `agents.currentInitiator`, traditional hosted search is unavailable with a named diagnostic; explicit marked `GenerateOptions` can still bind guarded inline requests, uncached if necessary. Credential notification during initial lazy discovery cannot distinguish own rotation from external account change via public status: fail closed with `WEB_PROVIDER_UNAVAILABLE` before probe/wire; a later user/driver request may retry, never automatically.
|
|
100
101
|
- The new native Copilot draft warning says Save adds another real group, not a second account. Public additive APIs cannot veto Add or disable Save; this is warning-only, not enforced single-route registration. Core Edit/Delete remain. Alpha.7 screenshots illustrate timestamps, not alpha.8 migration/search proof.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0-alpha.29 (prepared)
|
|
4
|
+
|
|
5
|
+
- Fix search settings drafts and pending saves being reset by parent renders: capture stable traced Settings/routing Remote faces once per registration (#148).
|
|
6
|
+
- Make ordinary Web search settings provider-only, rename the final default to Fallback provider, and save both routing choices in one namespace CAS without model discovery or a model prerequisite.
|
|
7
|
+
- Resolve independent Copilot search models from current account-owned Responses metadata in deterministic order, with at most three capability-probed candidates and one final query. Preserve allowlists, explicit overrides, account/owner proof, cancellation and fallback policy; never borrow a Chat/global default or hardcode model IDs.
|
|
8
|
+
- Preserve existing model overrides and offer a separate explicit reset to automatic selection. Classify safe save/conflict diagnostics without exposing raw Remote errors.
|
|
9
|
+
- Add real pinned Settings/Client-codec contracts, mounted React/Cordis lifecycle tests, and isolated built-browser before/after reproduction. These are not live OAuth/search, published-release or installed Desktop acceptance claims.
|
|
10
|
+
|
|
3
11
|
## 0.4.0-alpha.28 (prepared)
|
|
4
12
|
|
|
5
13
|
- Enforce plugin-owned estimated independent prompt and combined input/output budgets on the managed Copilot route while preserving advertised context capacity and native transport (#146).
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Source markers, local rc.1-backed focused tests and fifteen scoped exact-source
|
|
|
61
61
|
|
|
62
62
|
## Install and sign in
|
|
63
63
|
|
|
64
|
-
The commands below target the package version `0.4.0-alpha.
|
|
64
|
+
The commands below target the package version `0.4.0-alpha.29`. Versioned URLs describe the intended release artifacts, not proof that publication or local activation has completed; use them only once that Release and its checksums are available. Install into the profile you use (replace `web` when targeting another profile):
|
|
65
65
|
|
|
66
66
|
Before installing/updating, unpack the **checksum-verified** archive into a temporary directory and run its read-only composition preflight (replace all paths with absolute paths for the intended profile):
|
|
67
67
|
|
|
@@ -74,7 +74,7 @@ Include any launcher patch files with repeated `--patch /absolute/file` argument
|
|
|
74
74
|
For approved online installation, the supported CLI command is:
|
|
75
75
|
|
|
76
76
|
```sh
|
|
77
|
-
dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
77
|
+
dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/dsh-github-copilot-0.4.0-alpha.29.tgz
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
If registry access is blocked or unavailable, do not retry it through another network. Desktop-managed profiles may instead use the [controlled offline CLI procedure](./docs/npm-distribution.md#controlled-offline-cli-maintenance), with an approved, checksum-verified local Release and existing dependency cache (`--offline --ignore-scripts`). All preflight and approval requirements still apply.
|
|
@@ -139,7 +139,7 @@ Agents should treat the browser authorization as a human handoff, not as a token
|
|
|
139
139
|
5. Confirm **Signed in** and inspect the automatic discovery result before asking the user to choose a model. Already-signed-in Models opening ensures missing/stale metadata automatically; fresh ready cache makes no request. Use visible **Retry** for errors or **Manage → Refresh models** for an intentional forced update, not routine setup. Status alone does not discover, and login, metadata and successful model calls remain separate evidence.
|
|
140
140
|
6. Use **Sign out** only when the user explicitly asks to disconnect the account. It deletes the Copilot credential record but preserves route settings.
|
|
141
141
|
|
|
142
|
-
GitHub Releases and npm are the default distribution channels for each new version, using the same verified tarball. Pin the version and verify the evidence for the channel used: Release `SHA256SUMS`, and npm `dist.integrity` when installing from npm. The native Desktop package manager is preferred when permitted registry access is available; after npm publication is verified it accepts `dsh-github-copilot@0.4.0-alpha.
|
|
142
|
+
GitHub Releases and npm are the default distribution channels for each new version, using the same verified tarball. Pin the version and verify the evidence for the channel used: Release `SHA256SUMS`, and npm `dist.integrity` when installing from npm. The native Desktop package manager is preferred when permitted registry access is available; after npm publication is verified it accepts `dsh-github-copilot@0.4.0-alpha.29`, not a URL or file. Desktop-managed profiles also support explicitly approved [controlled offline CLI maintenance](./docs/npm-distribution.md#controlled-offline-cli-maintenance) with a verified local Release and `--offline --ignore-scripts`. Follow the mandatory search-composition preflight, backup, single-writer and post-install checks; do not bypass a corporate registry ban, disable TLS verification or restart without separate approval. Offline installation is not proof that npm networking/publication was repaired. See [distribution and publication requirements](./docs/npm-distribution.md).
|
|
143
143
|
|
|
144
144
|
No `copilot2api` process, external gateway, placeholder API key, pasted GitHub token, or separate `dsh-web-search-provider` installation is required.
|
|
145
145
|
|
|
@@ -158,7 +158,7 @@ DSH Core continues to own model selection, sandboxing, tools, attachments, and o
|
|
|
158
158
|
|
|
159
159
|
Under **Settings → Models → Model roles**, enable dedicated dual-model sessions, select two available account models, and save the profile-global settings. No workspace is needed to save. **Create session with this configuration** uses the application's current workspace, shown read-only; open a workspace first if none is current. There is no separate workspace dropdown and no first/recent-workspace fallback. The planner handles planning and acceptance; `copilot_execute` delegates implementation to a native continuable child with a fixed execution model. Configuration is off by default and affects only sessions created through this entry. It does not change the global default, existing sessions, credentials or the ordinary Subagent model-selection setting.
|
|
160
160
|
|
|
161
|
-
Unavailable models are not substituted. Uncertain creation retries keep the same request identity. The feature requires public role/session/subagent capabilities and is visibly unavailable when they are absent; historical package compatibility is not blanket certification of this optional flow. See [setup, lifecycle, limitations and evidence](./docs/dual-model.md). The feature is included in the `0.4.0-alpha.
|
|
161
|
+
Unavailable models are not substituted. Uncertain creation retries keep the same request identity. The feature requires public role/session/subagent capabilities and is visibly unavailable when they are absent; historical package compatibility is not blanket certification of this optional flow. See [setup, lifecycle, limitations and evidence](./docs/dual-model.md). The feature is included in the `0.4.0-alpha.29` candidate; source and fixture tests are not proof of publication or Desktop activation.
|
|
162
162
|
|
|
163
163
|
If the card says **Could not load model roles**, do not change model defaults to work around it: this is a failed settings load, distinct from unsupported capabilities or unavailable models. In particular, a `githubCopilotDualModel/view` HTTP 404 indicates missing Host Remote exposure, not that the feature is off. See [troubleshooting and verification](./docs/dual-model.md#loading-and-remote-troubleshooting).
|
|
164
164
|
|
|
@@ -226,7 +226,7 @@ Before a grant is persisted or reused, the Host normalizer rebuilds only pi-ai's
|
|
|
226
226
|
|
|
227
227
|
## Hosted search
|
|
228
228
|
|
|
229
|
-
Auto-mode native search identity comes from the captured initiating Session's effective request-header/config or explicit `GenerateOptions`, never the future global chat default. Fixed/
|
|
229
|
+
Auto-mode native search identity comes from the captured initiating Session's effective request-header/config or explicit `GenerateOptions`, never the future global chat default. Fixed/fallback Copilot search instead resolves its execution model inside the provider from current account metadata, while preserving a nonempty explicit `github-copilot.searchModel` override; it never borrows the Chat model or another Session's selection. Core `Agent.options` remains the activation seed: model selection overrides request/assembly, with effective config recorded in `Session.requestHeader().config` before tools. Without a proven initiating owner, traditional search is unavailable. After a new model is selected but before its next request, the previous header must not be treated as current prompt guidance. Per-owner plan caches keep different-model Sessions independent. An actual cold managed search first ensures the shared account metadata without force, then derives model facts and applies the existing account/protocol/allowlist/probe gates. Explicit marked `GenerateOptions` can still bind eligible inline requests, uncached when no owner is available, under all existing guards.
|
|
230
230
|
|
|
231
231
|
**Credential-change limit:** an OAuth notification during initial lazy metadata discovery cannot distinguish the discovery's own token rotation from an external account change through current public status. That first search deliberately fails closed with `WEB_PROVIDER_UNAVAILABLE`, before probe/wire work. A later user/driver request may retry with refreshed credentials; there is no automatic retry or promise of seamless first-attempt refresh.
|
|
232
232
|
|
|
@@ -241,14 +241,15 @@ The bundle composes a plugin-owned web-service facade while preserving the origi
|
|
|
241
241
|
|
|
242
242
|
A separate **Web search** card under **Settings → Models** controls routing across search backends. On older Core versions without the Models footer, it appears as **Settings → Web search**. The companion owns the namespaced policy (`github-copilot-search-routing`); it does not claim a global Core namespace. Removing the companion restores the original web service.
|
|
243
243
|
|
|
244
|
-
The **Search provider** selector offers **Auto — follow Chat** and the actual search providers registered through the routed facade. **
|
|
244
|
+
The **Search provider** selector offers **Auto — follow Chat** and the actual search providers registered through the routed facade. **Fallback provider** uses the same catalog, with an additional **None — no fallback** choice. These are search backends, not individual models: Copilot is one backend even when different account models can execute its search requests. Ordinary setup needs only these provider choices, not a separate search model.
|
|
245
245
|
|
|
246
246
|
- `github-copilot-search-routing.searchProvider: auto` follows the initiating Chat provider. Copilot's plugin-owned aliases retain their existing ownership and model-capability checks; other Chat provider IDs must exactly match a registered search provider ID. Names, suffixes and model families are never guessed. This convention does not promise the same model or account across independently registered providers.
|
|
247
247
|
- A concrete `searchProvider` ID pins the primary backend independently of Chat.
|
|
248
248
|
- `defaultSearchProvider` is only the final fallback when no primary matches or the primary search fails. It is attempted at most once, never retried when it is already the primary, and never replaces a successful empty result. `none` disables fallback without disabling the primary.
|
|
249
|
-
- Copilot selected explicitly or as the fallback
|
|
249
|
+
- Copilot selected explicitly or as the fallback automatically considers at most three eligible Responses candidates from current account route facts, sorted by model ID. The default capability probe must succeed before the final user query is sent once; metadata alone is not proof, and a failed final query is not replayed across models. This internal selection does not change Chat or global defaults. Other backends own their model configuration, if any.
|
|
250
|
+
- A saved nonempty `github-copilot.searchModel` remains authoritative; the plugin does not silently replace an invalid override. Its read-only details offer a separate explicit reset to automatic selection (`searchModel: ''`). Saving provider routing never changes this override.
|
|
250
251
|
|
|
251
|
-
Existing `searchMode: auto/fixed` settings remain readable without automatic writes. Legacy fixed mode preserves its old default as the primary; fixed plus `none` stays disabled. An explicit save writes the
|
|
252
|
+
Existing `searchMode: auto/fixed` settings remain readable without automatic writes. Legacy fixed mode preserves its old default as the primary; fixed plus `none` stays disabled. An explicit save writes both routing keys together with one revision-checked mutation; it does not require the Copilot settings namespace or fetch an account/model list. Stable Remote references keep enclosing page renders from resetting the draft. On a revision conflict, reload saved settings and reapply the intended choices; a rejected or unconfirmed response is not reported as success. Saving proves only configuration persistence, not live search capability. The UI explains that saving adopts the chosen final fallback, including possible API charges; legacy `github-copilot.searchFallback: none` failure-spending restrictions remain until that choice is saved. Unregistered saved IDs remain visible as unavailable instead of being silently substituted.
|
|
252
253
|
|
|
253
254
|
`github-copilot.routeWebSearch: false` still delegates to the original configured web service. Otherwise cancellation, unload and captured account-proof invalidation never authorize a fallback. Generic registered backends must honor cancellation; their public interface does not expose an internal pre-network authorization hook. The historical direct Copilot/DeepSeek path retains its stronger owned pre-dispatch guard. Neither path supplies another provider's credentials from Copilot sign-in.
|
|
254
255
|
|
|
@@ -335,7 +336,7 @@ Existing installations must follow the [single-route migration guide](./docs/sin
|
|
|
335
336
|
- **Canonical route says `not-configured`:** with configured login this is normal managed-only mode; inspect account discovery separately rather than creating a native profile.
|
|
336
337
|
- **Delete dialog stays on “Deleting…”:** this update does not prove that hang fixed. Do not repeatedly delete; after an authorized Host stop, inspect persisted settings and follow the migration guide before deciding whether any removal is still needed.
|
|
337
338
|
- **No Think text:** the provider may omit public summaries, but nonempty summaries must survive the Responses parser. Check selected effort and named errors. Empty disclosures are hidden only after completion; encrypted replay is never displayed. Reasoning/replay-bearing histories use native Core transport.
|
|
338
|
-
- **Hosted search unavailable:** for
|
|
339
|
+
- **Hosted search unavailable:** for explicit/fallback Copilot, inspect account discovery/probe diagnostics; ordinary setup no longer requires selecting a search model. A legacy override remains authoritative until you explicitly reset it to automatic selection. Auto following Copilot Chat still requires that initiating model to support search. The custom inline path is legacy-canonical only; a saved provider choice or normal managed chat success does not prove search support.
|
|
339
340
|
- **Legacy endpoint/key still present:** reconciliation preserves unowned fields by design. Review explicit migration; never force-remove an ownership marker.
|
|
340
341
|
|
|
341
342
|
## Package entries and source map
|
|
@@ -398,8 +399,8 @@ Report the published Release URL, version, tag/commit and verified asset SHA-256
|
|
|
398
399
|
`package.json` declares public npm distribution. A release tag must equal `v${package.json.version}`. Versions use standard SemVer prerelease labels (`alpha`, `beta`, or `rc`), each with its matching npm dist-tag; only stable versions use `latest`. The Release workflow performs the frozen install and complete verification gate, packs once (or recovers the original archive on retry), verifies `SHA256SUMS`, publishes the immutable GitHub Release and then publishes those same bytes to npm through OIDC. Either channel failing means delivery is incomplete. First package creation needs an authorized maintainer; staging requires an existing package and is not a first-package bootstrap. Historical releases are not republished.
|
|
399
400
|
|
|
400
401
|
```sh
|
|
401
|
-
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
402
|
-
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
402
|
+
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/dsh-github-copilot-0.4.0-alpha.29.tgz
|
|
403
|
+
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/SHA256SUMS
|
|
403
404
|
sha256sum --check SHA256SUMS
|
|
404
405
|
```
|
|
405
406
|
|
|
@@ -407,7 +408,7 @@ PowerShell can verify the same two downloaded files with:
|
|
|
407
408
|
|
|
408
409
|
```powershell
|
|
409
410
|
$expected = (Get-Content .\SHA256SUMS).Split()[0]
|
|
410
|
-
$actual = (Get-FileHash .\dsh-github-copilot-0.4.0-alpha.
|
|
411
|
+
$actual = (Get-FileHash .\dsh-github-copilot-0.4.0-alpha.29.tgz -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
411
412
|
if ($actual -cne $expected) { throw 'Release checksum mismatch' }
|
|
412
413
|
```
|
|
413
414
|
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
一个聚焦 GitHub Copilot 登录、通用账号模型发现、Copilot 专用 Tool 兼容与供应方托管搜索的 DSH companion。插件根据供应方返回的端点和能力元数据组装模型,复用公开的 `@deepseek-ai/dsh-llm-pi-ai` adapter 与 pi-ai SDK,不另写一套通用传输/序列化器,也不维护需要逐个添加新模型 ID 的静态目录。
|
|
11
11
|
|
|
12
|
-
> 下文自动维护账号模型元数据与 provider 集成控件描述目标版本 `0.4.0-alpha.
|
|
12
|
+
> 下文自动维护账号模型元数据与 provider 集成控件描述目标版本 `0.4.0-alpha.29`;这不代表已有的两条真实路由被合并或移除。版本化 URL 不表示 Release 已发布或本机已加载;仅在该 Release 与校验和可用后使用安装命令。源码、发布制品、已安装版本和实际加载运行时需分别确认,本地升级和中断会话的重启仍需用户批准。
|
|
13
13
|
|
|
14
14
|
Alpha.24 修复 Web search 卡片缺少精确 Remote 依赖声明的问题。卡片仍位于 **Settings → Models**(`settings.models.footer`,list/root),旧 Core 回退到独立 Web search section,而非 General。搜索子 Fiber 独立等待 routing namespace,不影响账号控件和既有搜索安全检查;实际打包 Desktop 验收仍是独立关卡。
|
|
15
15
|
|
|
@@ -76,7 +76,7 @@ node package/scripts/check-search-composition.mjs --profile-dir /absolute/profil
|
|
|
76
76
|
获准且网络可用时,可通过受支持的 CLI 命令安装:
|
|
77
77
|
|
|
78
78
|
```sh
|
|
79
|
-
dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
79
|
+
dsh plugin --profile web add https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/dsh-github-copilot-0.4.0-alpha.29.tgz
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
若 registry 被公司封禁或不可用,不要更换网络绕行。Desktop 管理的 profile 可以改用[受控离线 CLI 流程](./docs/npm-distribution.md#controlled-offline-cli-maintenance):使用来源获准、校验通过的本地 Release 和已有依赖缓存(`--offline --ignore-scripts`)。预检、备份和授权要求仍然适用。
|
|
@@ -141,7 +141,7 @@ Agent 应把浏览器授权视为需要用户完成的 handoff,而不是自行
|
|
|
141
141
|
5. 确认 **Signed in** 并检查自动发现结果,再请用户选择模型。已登录时打开 Models 会自动确保缺失/过期元数据,新鲜 ready 缓存不发请求。错误可使用 **Retry**,有意强制更新时使用 **Manage → Refresh models**,不作为常规设置步骤。状态读取本身不发现;登录、元数据与真实调用成功是独立证据。
|
|
142
142
|
6. 只有用户明确要求断开账号时才使用 **Sign out**;它会删除 Copilot credential record,但保留 route settings。
|
|
143
143
|
|
|
144
|
-
每个新版本默认同时分发到 GitHub Releases 和 npm,两个渠道使用同一份已验证 tarball。应固定版本并核对所用渠道的证据:Release 的 `SHA256SUMS`;从 npm 安装时另核对 `dist.integrity`。在获准且可用的 registry 网络环境中,优先使用原生 Desktop 包管理器;确认 npm 发布后,它接受 `dsh-github-copilot@0.4.0-alpha.
|
|
144
|
+
每个新版本默认同时分发到 GitHub Releases 和 npm,两个渠道使用同一份已验证 tarball。应固定版本并核对所用渠道的证据:Release 的 `SHA256SUMS`;从 npm 安装时另核对 `dist.integrity`。在获准且可用的 registry 网络环境中,优先使用原生 Desktop 包管理器;确认 npm 发布后,它接受 `dsh-github-copilot@0.4.0-alpha.29`,不是 URL 或本地文件。Desktop 管理的 profile 也允许经明确授权的[受控离线 CLI 维护](./docs/npm-distribution.md#controlled-offline-cli-maintenance):使用已验证的本地 Release 和 `--offline --ignore-scripts`,执行必需的组合预检、私密元数据备份、单写入者控制及安装后差异核验。缓存不足或出现权限拒绝时停止,不绕过公司 registry 封禁,不关闭 TLS 校验;重启仍需单独授权。离线安装成功不表示 npm 联网或发布问题已修好。[双渠道发布与 OIDC 要求](./docs/npm-distribution.md)保持不变。
|
|
145
145
|
|
|
146
146
|
不需要运行 `copilot2api`,不需要外部 gateway、placeholder API key、原始 GitHub token 或单独安装 `dsh-web-search-provider`。
|
|
147
147
|
|
|
@@ -162,7 +162,7 @@ DSH Core 继续负责模型选择、sandbox、工具、附件与其它 provider
|
|
|
162
162
|
|
|
163
163
|
在 **设置 → 模型 → 模型分工** 中启用双模型会话,选择账号下可用的主模型和执行模型,保存全局设置(同一配置档案内通用,不按工作区保存)。保存不需要工作区;**用此配置新建会话** 使用应用当前工作区,并只读显示目标。没有当前工作区时须先打开工作区,不再提供独立下拉框,也不会默认选择第一个或最近的工作区。主模型负责规划与验收;`copilot_execute` 创建原生可继续执行的子代理,并固定其执行模型。默认关闭,仅专用入口创建的新会话采用此策略;不修改全局默认、已有会话、登录凭据或原生 Subagent 授权开关。
|
|
164
164
|
|
|
165
|
-
模型不可用时明确报错,不自动替换。创建结果不明时重试同一个请求,不为绕过未知结果另建会话。功能依赖公开的会话、策略和子代理能力;缺少接口时显示不可用,不把历史版本的包兼容范围当成此功能的全面验收。详见[配置、生命周期、限制与验证范围](./docs/dual-model.md)。本功能包含在 `0.4.0-alpha.
|
|
165
|
+
模型不可用时明确报错,不自动替换。创建结果不明时重试同一个请求,不为绕过未知结果另建会话。功能依赖公开的会话、策略和子代理能力;缺少接口时显示不可用,不把历史版本的包兼容范围当成此功能的全面验收。详见[配置、生命周期、限制与验证范围](./docs/dual-model.md)。本功能包含在 `0.4.0-alpha.29` candidate 中,源码和合成测试不代表已发布或当前 Desktop 已生效。
|
|
166
166
|
|
|
167
167
|
若卡片显示 **Could not load model roles(无法加载模型分工)**,不要通过修改默认模型绕过:这是设置加载失败,与能力不支持或模型不可用不同。尤其 `githubCopilotDualModel/view` 返回 HTTP 404,表示 Host Remote 未暴露,并非功能开关处于关闭状态。详见[加载故障排查与验证](./docs/dual-model.md#loading-and-remote-troubleshooting)。
|
|
168
168
|
|
|
@@ -234,7 +234,7 @@ Grant 写入或复用前,Host normalizer 只会把 pi-ai 文档化的 `type`
|
|
|
234
234
|
|
|
235
235
|
## Hosted search
|
|
236
236
|
|
|
237
|
-
`auto` 模式的原生搜索身份来自捕获的发起 Session 有效 request-header/config 或显式 `GenerateOptions
|
|
237
|
+
`auto` 模式的原生搜索身份来自捕获的发起 Session 有效 request-header/config 或显式 `GenerateOptions`,绝不使用未来全局聊天默认值;固定/兜底 Copilot 搜索则在 Provider 内部根据当前账号元数据解析执行模型,同时保留非空的显式 `github-copilot.searchModel` 覆盖值;不会借用 Chat 模型或另一个 Session 的选择。Core `Agent.options` 仍是激活时的 seed;模型选择覆盖 request/assembly,有效配置在工具调用前记录到 `Session.requestHeader().config`。没有可证明的发起 owner 时,传统搜索不可用。新模型已选择但下一次请求尚未开始时,不能把旧 header 当作当前 prompt 指引。按 owner 隔离的 plan 缓存保留不同模型 Session 的独立性;真实托管搜索冷启动时先非强制确保共享账号元数据,再派生模型事实并检查既有账号/协议/allowlist/probe。显式带标记的 `GenerateOptions` 仍可绑定符合条件的 inline 请求,没有 owner 时可不缓存,但保留所有既有检查。
|
|
238
238
|
|
|
239
239
|
**凭据变化限制:**初次惰性元数据发现期间出现 OAuth 通知时,现有公开状态无法区分发现自身的 token 轮换与外部换号。该次搜索会在 probe/wire 前以 `WEB_PROVIDER_UNAVAILABLE` 保守失败;之后用户/driver 可重新请求并使用已刷新的凭据,不自动重试,也不承诺首次刷新无缝成功。
|
|
240
240
|
|
|
@@ -249,14 +249,15 @@ Grant 写入或复用前,Host normalizer 只会把 pi-ai 文档化的 `type`
|
|
|
249
249
|
|
|
250
250
|
**设置 → 模型**下新增独立的 **Web search** 卡片;旧版 Core 没有 Models footer 时,使用独立的 **设置 → Web search** 分区。策略由本插件的 `github-copilot-search-routing` 命名空间持有,不占用 Core 通用命名空间;卸载本插件后恢复原 web 服务。
|
|
251
251
|
|
|
252
|
-
**Search provider** 主选择器提供 **Auto — follow Chat** 和通过路由外观层实际注册的搜索 Provider;**
|
|
252
|
+
**Search provider** 主选择器提供 **Auto — follow Chat** 和通过路由外观层实际注册的搜索 Provider;**Fallback provider**(兜底后端)使用同一目录,额外提供 **None — no fallback**。选择项代表搜索后端,不代表单个模型:即使多个账号模型可以执行搜索,Copilot 仍然只有一个搜索后端。普通配置只需选择这两个 Provider,不再要求另选搜索模型。
|
|
253
253
|
|
|
254
254
|
- `github-copilot-search-routing.searchProvider: auto` 跟随发起 Chat 的 Provider。本插件自有 Copilot 别名保留既有 owner 和模型能力检查;其他 Chat Provider 的原始 ID 必须精确匹配已注册的搜索 Provider ID,不猜名字、后缀或模型家族。这是路由约定,不承诺独立注册的后端一定使用相同模型或账号。
|
|
255
255
|
- 将 `searchProvider` 设为具体 ID,就固定主搜索后端,不再随 Chat 改变。
|
|
256
256
|
- `defaultSearchProvider` 仅在无匹配主后端或主搜索失败时作最终兜底,最多尝试一次;与主后端相同时不重试,成功但结果为空也不触发兜底。`none` 仅关闭兜底,不关闭主搜索。
|
|
257
|
-
- 显式选择 Copilot
|
|
257
|
+
- 显式选择 Copilot 或将它作为兜底时,内部按模型 ID 排序,从当前账号路由事实中最多考虑三个符合条件的 Responses 候选。默认要求能力 probe 成功后才发送一次用户的最终查询;元数据本身不是能力证明,最终查询失败也不会跨模型重放。内部选择不改变 Chat 或全局默认模型。其他后端自行管理模型配置(若有)。
|
|
258
|
+
- 已保存的非空 `github-copilot.searchModel` 仍具有优先权;覆盖值无效时不会静默换成其他模型。只读详情提供独立、显式的恢复自动选择操作(`searchModel: ''`);保存 Provider 路由绝不修改该覆盖值。
|
|
258
259
|
|
|
259
|
-
旧 `searchMode: auto/fixed` 配置继续兼容读取,不自动写入。旧 fixed 保留原 default 作为主后端;fixed 加 `none`
|
|
260
|
+
旧 `searchMode: auto/fixed` 配置继续兼容读取,不自动写入。旧 fixed 保留原 default 作为主后端;fixed 加 `none` 继续禁用。用户明确保存后,通过一次带修订号校验的 mutation 同时写入两个路由键,不依赖 Copilot 设置命名空间,也不读取账号/模型列表。稳定的 Remote 引用避免外层页面重渲染重置草稿。发生修订冲突时,应重新加载已保存配置并重新应用所需选择;拒绝或未确认的响应不会被报告为成功。保存只证明配置持久化,不证明真实搜索能力。界面会说明保存将采用选中的最终兜底并可能产生 API 费用;旧的 `github-copilot.searchFallback: none` 失败兜底付费限制保留到明确保存新选择为止。已保存但未注册的 ID 保持显示为不可用,不静默替换。
|
|
260
261
|
|
|
261
262
|
`github-copilot.routeWebSearch: false` 仍委托原始 web 服务。其余情况下,取消、卸载及捕获的账号证明失效都不能触发兜底。通用注册后端必须遵守取消信号,但公开接口没有提供其内部鉴权后、网络发送前的检查钩子;历史 Copilot/DeepSeek 直调路径保留更强的自有发送前保护。两条路径都不会用 Copilot 登录替其他 Provider 提供凭据。
|
|
262
263
|
|
|
@@ -346,7 +347,7 @@ Copilot Session 如需更宽的文件或命令权限,必须在调用前选择
|
|
|
346
347
|
- **Canonical 状态为 `not-configured`:**已登录时属于正常单托管路由模式;账号发现就绪与否另行检查,不需要创建原生 profile。
|
|
347
348
|
- **删除对话框一直显示 “Deleting…”:**本次改动不证明该卡住问题已修复。不要重复删除;取得许可停止 Host 后检查持久化设置,按迁移指南判断是否仍需移除。
|
|
348
349
|
- **没有 Think 文字:**供应方可能不返回公开摘要,但非空摘要应被完整保留。检查思考强度与命名错误。UI 只在完成后隐藏空条目,不显示加密回放;包含 reasoning/replay 的历史走 Core 原生 transport。
|
|
349
|
-
- **Hosted search
|
|
350
|
+
- **Hosted search 不可用:**显式/兜底 Copilot 应检查账号发现与 probe 诊断,普通设置不再要求手选搜索模型。旧覆盖值在明确恢复自动选择前仍具有优先权。Auto 跟随 Copilot Chat 时仍要求发起模型支持搜索。自定义 inline 仅适用于仍配置的旧 canonical 路由;保存 Provider 选择或普通聊天成功不能证明搜索可用。
|
|
350
351
|
- **仍有旧 endpoint/key:**reconciliation 有意保留非本包所有的字段;按显式迁移审核,不要强删所有权 marker。
|
|
351
352
|
|
|
352
353
|
## Package 入口与源码映射
|
|
@@ -409,8 +410,8 @@ node scripts/agent.mjs attribution "DeepSeek Harness (DSH)"
|
|
|
409
410
|
`package.json` 声明公开 npm 分发。Release tag 必须严格等于 `v${package.json.version}`。预发布使用 `alpha`、`beta` 或 `rc` 及对应 npm dist-tag,只有稳定版使用 `latest`。Release workflow 执行 frozen install 和完整门禁,只打包一次(重试恢复原始归档),验证 `SHA256SUMS`,发布不可变 GitHub Release,再通过 OIDC 将同一份字节发布到 npm。任一渠道失败都表示交付未完成。首次建包须由获准环境中的维护者完成;staging 要求包已存在,不能代替首次建包。不会批量补发历史版本。
|
|
410
411
|
|
|
411
412
|
```sh
|
|
412
|
-
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
413
|
-
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.
|
|
413
|
+
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/dsh-github-copilot-0.4.0-alpha.29.tgz
|
|
414
|
+
curl -LO https://github.com/cloga/dsh-github-copilot/releases/download/v0.4.0-alpha.29/SHA256SUMS
|
|
414
415
|
sha256sum --check SHA256SUMS
|
|
415
416
|
```
|
|
416
417
|
|
|
@@ -418,7 +419,7 @@ PowerShell 可以对已下载的同一组文件执行:
|
|
|
418
419
|
|
|
419
420
|
```powershell
|
|
420
421
|
$expected = (Get-Content .\SHA256SUMS).Split()[0]
|
|
421
|
-
$actual = (Get-FileHash .\dsh-github-copilot-0.4.0-alpha.
|
|
422
|
+
$actual = (Get-FileHash .\dsh-github-copilot-0.4.0-alpha.29.tgz -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
422
423
|
if ($actual -cne $expected) { throw 'Release checksum mismatch' }
|
|
423
424
|
```
|
|
424
425
|
|
package/deployment-baseline.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"package": {
|
|
10
10
|
"name": "dsh-github-copilot",
|
|
11
|
-
"version": "0.4.0-alpha.
|
|
11
|
+
"version": "0.4.0-alpha.29"
|
|
12
12
|
},
|
|
13
13
|
"evidence": {
|
|
14
14
|
"kind": "source-and-synthetic-test-inventory",
|
|
@@ -284,6 +284,34 @@
|
|
|
284
284
|
{"file": "tests/routed-web-loader.spec.ts", "name": "loads the built facade and delegate entries without changing official tools"}
|
|
285
285
|
]
|
|
286
286
|
},
|
|
287
|
+
{
|
|
288
|
+
"id": "provider-only-search-settings",
|
|
289
|
+
"required": true,
|
|
290
|
+
"evidenceScope": "pinned-settings-and-client-contracts-plus-synthetic-routing-no-live-save-claim",
|
|
291
|
+
"sourceMarkers": [
|
|
292
|
+
{"file": "src/client.ts", "marker": "const settings = ctx.remote.settings"},
|
|
293
|
+
{"file": "src/client.ts", "marker": "const routing = ctx.remote.githubCopilotSearchRouting"},
|
|
294
|
+
{"file": "src/web-search-routing-card.ts", "marker": "Fallback provider"},
|
|
295
|
+
{"file": "src/web-search-routing-card.ts", "marker": "data-dsh-copilot-search-reset"},
|
|
296
|
+
{"file": "src/index.ts", "marker": "function configuredCandidates(cfg: InlineConfig)"}
|
|
297
|
+
],
|
|
298
|
+
"tests": [
|
|
299
|
+
{"file": "tests/web-search-routing-card.spec.ts", "name": "saves Copilot as %s with one routing write and no model prerequisite"},
|
|
300
|
+
{"file": "tests/web-search-routing-card.spec.ts", "name": "does not rewrite a legacy model override when saving provider routing"},
|
|
301
|
+
{"file": "tests/web-search-routing-card.spec.ts", "name": "never loads account model suggestions to display or save providers"},
|
|
302
|
+
{"file": "tests/web-search-routing-card.spec.ts", "name": "resets a legacy override only through an explicit separate action"},
|
|
303
|
+
{"file": "tests/web-search-routing-card.spec.ts", "name": "explains a real Remote settings-conflict without exposing its raw details"},
|
|
304
|
+
{"file": "tests/client-search-inject.spec.ts", "name": "keeps real mounted drafts and pending saves through parent rerenders (footer=%s)"},
|
|
305
|
+
{"file": "tests/scripts/search-settings-contract.test.mjs", "name": "real pinned Client namespace lookups require stable capture across render calls"},
|
|
306
|
+
{"file": "tests/scripts/search-settings-contract.test.mjs", "name": "provider-only search routing saves both leaves once without a Copilot namespace or model"},
|
|
307
|
+
{"file": "tests/scripts/search-settings-contract.test.mjs", "name": "stale routing revisions fail CAS and preserve the last successful settings"},
|
|
308
|
+
{"file": "tests/scripts/search-settings-contract.test.mjs", "name": "hidden legacy searchModel is writable and accepts an explicit empty reset"},
|
|
309
|
+
{"file": "tests/scripts/search-settings-contract.test.mjs", "name": "pinned generated Client mutate codecs accept routing ops and a flat namespace revision"},
|
|
310
|
+
{"file": "tests/inline/apply.spec.ts", "name": "automatically resolves account-owned Responses candidates for %s without a search model"},
|
|
311
|
+
{"file": "tests/inline/apply.spec.ts", "name": "bounds automatic proof to three eligible candidates in deterministic id order"},
|
|
312
|
+
{"file": "tests/inline/apply.spec.ts", "name": "does not discover or probe allowlist-excluded automatic search"}
|
|
313
|
+
]
|
|
314
|
+
},
|
|
287
315
|
{
|
|
288
316
|
"id": "explicit-deepseek-search-fallback",
|
|
289
317
|
"required": true,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Requested behavior
|
|
4
4
|
|
|
5
|
-
Issue #135 separates the primary search provider from the final fallback. `github-copilot-search-routing.searchProvider` is `auto` or an exact registered search-provider ID; `defaultSearchProvider` is an independent ID or `none`. Auto follows the initiating Chat provider, never the global default. Copilot's owned aliases retain their existing account/model checks; other Chat IDs must exactly match an observed search registration, without name/suffix/model-family inference. This is a provider-level convention, not a promise of the same execution model or account across independent registries. GPT, Gemini and Grok models do not each become a separate Copilot search provider.
|
|
5
|
+
Issue #135 separates the primary search provider from the final fallback. `github-copilot-search-routing.searchProvider` is `auto` or an exact registered search-provider ID; `defaultSearchProvider` is an independent ID or `none`. Auto follows the initiating Chat provider, never the global default. Copilot's owned aliases retain their existing account/model checks; other Chat IDs must exactly match an observed search registration, without name/suffix/model-family inference. This is a provider-level convention, not a promise of the same execution model or account across independent registries. GPT, Gemini and Grok models do not each become a separate Copilot search provider. Issue #148 makes ordinary settings provider-only: explicit/fallback Copilot resolves account-owned Responses candidates internally unless a nonempty legacy `github-copilot.searchModel` override is present.
|
|
6
6
|
|
|
7
7
|
All implementation belongs to this plugin. No Core source, deployed Core artifact, prototype, private registry, credential copy or global chat-model choice is modified. The original official WebRuntime configuration, including its selected search/fetch providers, is preserved. The routed facade mirrors public search-provider registrations so exact-id selection works for official and community providers without reading Core's private registry.
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ Modern Core may mount `tool-web` in agent presets while disabling its historical
|
|
|
13
13
|
1. An id-and-name-guarded patch moves the existing `web` / `@deepseek-ai/dsh-web` row into the named `github-copilot-original-web` service realm without replacing its config.
|
|
14
14
|
2. The plugin's `web-delegate` entry exposes that same official service through a public, Fiber-owned bridge. It does not read any provider registry internals.
|
|
15
15
|
3. The plugin-owned `routed-web` service occupies the ordinary Host `web` scope. It forwards provider registration and fetch to the original service while retaining Fiber-scoped handles for exact-id search dispatch.
|
|
16
|
-
4. Auto-mode Copilot searches use the captured initiating-session route. Fixed/
|
|
16
|
+
4. Auto-mode Copilot searches use the captured initiating-session route. Fixed/fallback Copilot searches preserve a nonempty explicit provider-owned `searchModel`, otherwise use bounded automatic selection from current account-owned Responses route facts. Other provider ids dispatch through the mirrored public registration. A separate private official WebRuntime supplies native request validation and source capping on every routed branch.
|
|
17
17
|
5. Native `tool-web` consumers, including those in agent presets, retain their original schemas, configured query/source limits, batching, execution policies, timeout metadata, formatting and presentation.
|
|
18
18
|
|
|
19
19
|
This is a plugin-owned subclass and explicit public service composition, not a replacement of Core prototypes or a mutation of a live registered service. It affects all `ctx.web.search` consumers with eligible Copilot context, not only one tool name. The bundle requires the standard enabled top-level official Host `web` row, static provider config and no prior isolation. The patch name guard does not make its separate inserted rows conditional: installing into a custom/missing/disabled/isolated web composition can prevent startup. Run the required read-only `scripts/check-search-composition.mjs` preflight over the existing profile before installing; it uses public readers and composition without calling write-capable `loadProfile` normalization. It compares a routing-free baseline with the actual post-install candidate at the existing bundle position (or the append position for first install), including profile, home and supplied launcher patches. Nonempty disposable `cordis.yml` roots are refused because normal CLI launch resets them; late isolation resets or an original web row inserted only after the routing guard are also refused. `dsh plugin add` does not automatically enforce this step. Unsupported shapes must be refused before mutation, not described as safe no-ops.
|
|
@@ -28,13 +28,19 @@ Fallback notices remain inside canonical `WebSearchResult.content`, so Core resu
|
|
|
28
28
|
|
|
29
29
|
Legacy direct callers without the facade capture seam keep the historical `src/search-routing.ts` Copilot/DeepSeek path only for legacy policy. Its `src/deepseek-search-fallback.ts` constructs the unchanged public official adapter and retains its safe URL validation, exact option snapshot, credential ownership and post-auth/pre-fetch guard. The new catalog-based path instead calls the actual registered backend; an identical ID does not authorize replacing it with that factory. Generic `search()` exposes no internal authentication/pre-network hook, so do not claim the stronger legacy guard for arbitrary third-party implementations.
|
|
30
30
|
|
|
31
|
-
`src/search-routing-policy.ts` normalizes settings without writes: a new explicit `searchProvider` wins; old auto remains Auto; old fixed preserves its default as primary; old fixed plus `none` stays disabled. Unknown saved IDs remain visible and fail closed at dispatch. Until an explicit UI save adopts the new fallback choice, legacy `searchFallback: none` preserves its failure-spending restriction. The save
|
|
31
|
+
`src/search-routing-policy.ts` normalizes settings without writes: a new explicit `searchProvider` wins; old auto remains Auto; old fixed preserves its default as primary; old fixed plus `none` stays disabled. Unknown saved IDs remain visible and fail closed at dispatch. Until an explicit UI save adopts the new fallback choice, legacy `searchFallback: none` preserves its failure-spending restriction. The ordinary save commits both primary and fallback leaves together in one CAS mutation of the routing namespace. It neither requires nor writes the Copilot settings namespace, and it performs no account-status/model-discovery RPC or capability probe. A nonempty legacy `searchModel` remains authoritative and visible read-only; only the separate explicit reset sets `searchModel: ''` with that namespace's own revision. A failed reset must not prevent an unrelated routing save. Missing namespaces, read-only deployments, stale revisions and uncertain responses must remain visible without exposing raw provider errors. `routeWebSearch: false`, the master enable switch, Copilot allowlists and capability proof keep their existing responsibilities.
|
|
32
32
|
|
|
33
33
|
## Search directory and settings UI
|
|
34
34
|
|
|
35
|
-
Both selectors use `githubCopilotSearchRouting.providers()`, a separate strict Remote exposed through the public `TypertRemoteService` binding. Its catalog contains only fresh IDs from registrations observed by this facade, not Core private registry objects or hidden/direct-original registrations. The read invokes no `available()`, auth, discovery or search: availability is contextual and checked on actual use. A missing facade yields `supported: false`, not a static example list. Newly registered IDs appear on reload; removed saved entries remain visibly unavailable. Primary adds Auto;
|
|
35
|
+
Both selectors use `githubCopilotSearchRouting.providers()`, a separate strict Remote exposed through the public `TypertRemoteService` binding. Its catalog contains only fresh IDs from registrations observed by this facade, not Core private registry objects or hidden/direct-original registrations. The read invokes no `available()`, auth, discovery or search: availability is contextual and checked on actual use. A missing facade yields `supported: false`, not a static example list. Newly registered IDs appear on reload; removed saved entries remain visibly unavailable. Primary adds Auto; **Fallback provider** adds None while retaining the stored `defaultSearchProvider` key. The ordinary card has no model selector. Settings and routing Remote faces are captured once at UI registration: real pinned Cordis/Client Gateway namespace reads return fresh traced proxies, so looking them up in each render would change effect dependencies and reload drafts. Models remain provider internals, not additional search-provider entries.
|
|
36
36
|
|
|
37
|
-
Focused postbuild checks must run after `pnpm build`. `tests/search-provider-catalog.spec.ts` checks registration lifecycle, duplicate handling and read purity; `tests/scripts/search-provider-gateway.test.mjs` drives the real Connection Fetch/Gateway against the packaged facade
|
|
37
|
+
Focused postbuild checks must run after `pnpm build`. `tests/search-provider-catalog.spec.ts` checks registration lifecycle, duplicate handling and read purity; `tests/scripts/search-provider-gateway.test.mjs` drives the real Connection Fetch/Gateway against the packaged search-catalog facade/controller. `tests/web-search-routing-card.spec.ts` covers both selectors, unavailable catalogs, one routing CAS without a model prerequisite, explicit separate override reset, safe conflict messages, legacy choices and stale generations. `tests/client-search-inject.spec.ts` mounts the actual Client callback with real React DOM and Cordis in jsdom, checking draft and pending-save continuity through parent rerenders for both footer and legacy section slots; its Remote transport remains synthetic. `tests/scripts/search-settings-contract.test.mjs` uses the real pinned Settings service with in-memory persistence and the unchanged generated Client codecs: two-leaf routing writes, stale CAS, writable hidden/empty legacy overrides and the flat returned namespace revision. It also mounts the real pinned Client Gateway/Remote descriptors to verify traced proxy identity, without RPC or streams. It does **not** execute the actual Host SettingsController write through Gateway. An isolated Edge reproduction with the old alpha.28 built card and actual registration callback, backed by synthetic fresh Remote getters, reproduced both a filled-model draft resetting on a parent render and a completed model write whose subsequent routing write was abandoned on a parent render. This establishes a reproducible plugin lifecycle defect, not a definitive diagnosis of the user's production runtime. The corrected built card passed the same isolated Edge rerender/save/reload flow without a model field or account-status RPC, plus explicit legacy override reset, safe CAS conflict recovery, read-only state, dark/light desktop and 375px mobile captures, and a 200% zoom overflow check. These fixtures are not live account, installed Desktop or paid model evidence. The final local `pnpm verify` passed with one test worker: 62 Vitest files, 1553 passing tests and 2 expected skips, 273 tooling tests, source/test typechecks, baseline checks, build and package smoke. An earlier unrestricted parallel run hit three import-time test timeouts; the unchanged tests passed with bounded concurrency, without extending timeouts or skipping assertions. Remote CI, release publication and loaded-runtime acceptance remain separate pending checks.
|
|
38
|
+
|
|
39
|
+
## Provider-owned automatic Copilot selection (#148)
|
|
40
|
+
|
|
41
|
+
For explicit/fallback Copilot without a nonempty `searchModel`, an actual search non-forcing ensures current account metadata under the existing ownership, TTL, cooldown and credential guards. Eligible account-owned Responses routes are considered in deterministic model-ID order, with at most three candidates. No static model-name table, another Session's model, global Chat default or UI model list supplies the selection. A nonempty override remains the sole candidate and is not silently replaced if unavailable.
|
|
42
|
+
|
|
43
|
+
Metadata determines eligibility, not native-search support. With the default `probe: true`, bounded candidate proof must succeed before one final user-query request is sent. Candidate proof is not a loop replaying the user's query; a final request failure is not retried on another model. The explicit `probe: false` trust override retains its existing meaning and is not a recovery recommendation. Empty/incomplete account evidence, unsupported protocols and proof exhaustion fail closed; cancellation or captured account-proof invalidation terminates the operation. Auto following a Copilot Chat route continues to use the captured initiating model rather than this independent selection. Existing outer primary/final-fallback policy, no-repeat backend rule and charge disclosures remain unchanged. Reusable successful proofs retain only account/owner lifetime, not the creating request's deadline or cancellation. Concurrent configured callers own separate unfinished probes; canceling one must not abort another, and a canceled probe is never reused as negative capability evidence.
|
|
38
44
|
|
|
39
45
|
## Review hardening
|
|
40
46
|
|