* feat(web-shell): support host settings item allowlists * fix(web-shell): match every setting alias and warn on unknown item ids Review follow-ups for the host settings allowlists: - isSettingVisible collects every alias mapped to a key instead of the first, so a second stable alias keeps working; exclusion still wins. - Warn once per unrecognized include/exclude id in development instead of dropping it silently (dev-only, compiled out of the published build, no new exports). - Pin the allowlist permit direction for settings-launched pickers and Add Model, the builtin:connections filter mapping, and the full published alias-to-key table. - Make the settings browser spec fully descriptor-driven instead of matching on case names. - Cross-link the superseded exclusions design doc and note that builtin:connections only renders in the standalone build. * fix(web-shell): ship the unknown settings id warning in production builds The warnUnknownItemIds guard was gated on import.meta.env.DEV, which the library build folds to false, so the whole diagnostic was dead-code eliminated from dist/index.js — the only artifact embedding hosts install. A runtime typo in includeItems/excludeIds then rendered the generic empty state with no console diagnostic. - Drop the DEV gate; the once-per-id dedup keeps production output to one line per distinct unknown id, and empty lists still never warn. - Run the warn-once test under both DEV modes via vi.stubEnv so the shipped behavior is pinned (red on the gated source when DEV=false). - Assert the excludeItems half of the validation loop with an unknown exclusion id (the spread was previously unwitnessed). - Pin the permit direction for the settings-launched voice picker: open it under includeItems: ['setting:voice-model'] and keep it open across a still-including rerender. --------- Co-authored-by: 铃蓝 <[email protected]> Co-authored-by: qwen-code-ci-bot <[email protected]>
4.1 KiB
Embedded settings allowlists
Problem and scope
Issue #12320 follows the exclusions shipped in #11975. Hosts exposing a small settings surface must currently enumerate everything else, and upgrades expose new settings automatically. Add an optional presentation allowlist using the existing stable IDs. No daemon protocol, saved settings, underlying feature activation, capability checks, ordering, or independent command behavior changes.
Design and decisions
Add includeItems?: readonly WebShellSettingItemId[] alongside excludeItems. Missing inclusion means the existing behavior; an empty inclusion list intentionally hides every native settings item and uses the existing empty state without a warning. Otherwise show only eligible included items, with exclusions winning on conflict. Both ordinary settings and builtin blocks follow the same policy in both scopes.
Retaining the shipped exclusion API avoids migration. A mode discriminator would either replace that API or introduce another overlapping shape. An empty host-generated allowlist must not unexpectedly expose everything. These are presentation filters, not access control: commands and daemon writes remain available and no saved values change.
Centralize policy in positive isItemVisible and isSettingVisible predicates. Unaliased schema keys remain visible without an allowlist for compatibility, but are hidden whenever an allowlist is configured. Unknown runtime IDs cannot enable unmapped settings. Existing hardcoded and capability filters run before presentation filtering.
Use the same predicates in category filtering, settings picker entry guards, pending voice-picker checks, and dynamic dialog closure. Empty categories disappear; selection falls back to a remaining category. Independently launched command dialogs remain available. The browser harness must distinguish an absent include parameter from an empty one.
Files and compatibility
Change the web-shell settings helpers and their consumers in App and SettingsMessage, focused helper/DOM/App/wrapper tests, the existing settings browser harness/spec, and the embedding README. Public options already flow through the provider wrappers. No new package dependencies or parent submodule changes are needed.
Verification and acceptance
Verify default and exclusion-only compatibility, empty allowlists, ordinary/builtin inclusion, exclusion precedence, unknown and inherited IDs, unaliased keys, capability filtering, both scopes, category fallback, and dynamic picker cleanup including pending voice requests. Run browser checks with real daemon descriptors at desktop/mobile widths, preserving the existing exclusion regression. Capture visible examples. Build, typecheck, bundle, run focused tests and full preflight before submitting a draft PR, recording any failures. Review the entire diff in two clean self-audit passes and an independent review.
Status and open questions
2026-09-20: implemented on d52b409dcd, following the issue's automated review and the host author's explicit request to proceed. A draft PR will present executable behavior for review; maintainer confirmation of the public API remains pending. The original exclusions design records the earlier phase; this document describes its allowlist extension.
Browser evidence
Real daemon settings descriptors were replayed through an isolated browser harness with synthetic session data. All six scenarios passed in both scopes: default, exclude-all, desktop allowlist, empty allowlist, conflict, and mobile allowlist. Screenshots below show the current implementation without an allowlist as a compatibility comparison, then language/chat-width inclusion at 1280×900 and 390×844, and the empty state. These checks do not claim real-provider model execution.



