Review round on #3316: the composition inventory answers from a standing
mount before the broken verdict (a file corrupted after mounting no longer
hides the running composition), livePresetMounts filters by the caller's
root fiber so a second Cordis runtime in one process never answers for it,
compositions carry trust and the plugin list resolves shipped preset names
through the shared dsh-agent-presets/display fold over ui-agent-preset's
dictionaries (INLINE_SAFE inline import; no cross-plugin runtime import),
the condition detail label reads Disabled when/禁用条件, and the stale
four-surfaces comment says three.
Review-driven refinements to the scope-grouped plugin list:
- The preset switcher becomes the General-settings selector pill over the
shared Menu primitive instead of a native select, and the preset group
is collapsible like the global one (search still forces both open).
- The session-plugins drawer is removed: rows the presets took over sit
inline in the global list with the preset-provided tag and per-preset
details, since the preset group above already shows those compositions.
- The status dot renders only for a live root fiber, so file-state rows
of an unmounted preset carry their enablement tag alone instead of a
column of grey dots.
- PresetTree reclaims the owning entry's subtree slot: EntryTree's
constructor filed the standing mount under the roster's own Loader row,
so after the first session composed a preset the whole composition
leaked into root loader.entries() as host rows (each preset overwriting
the last). A regression test holds the root entry list identical across
a mount.
The settings plugin list projected ctx.loader.entries() alone, hiding the
plugins sessions actually run and rendering the web overlay's deliberate
disabled tombstones (tool-bash, tool-fs, ...) as two dozen plainly disabled
rows while the same modules ran in every standard-preset session.
- dsh-agent-presets: compositionInventory() answers flattened rows per
preset — newest live standing generation when mounted, composition file
otherwise with !!js disabled gates evaluated against the Loader context;
reading never mounts (regression-tested), refusal stays 'conditional',
raced files report broken with the reason.
- dsh-host-plugin-inventory: list() gains an optional agentPresets block,
resolving the roster as an optional peer and mapping fiber states to the
public phase vocabulary.
- ui-settings-plugin-inventory: preset group first behind a display-only
switcher opening on the default preset; global group collapsed with
failures floated; host-disabled modules enabled by >=1 preset fold into a
session-plugins drawer naming providers; search spans scopes and points
at matches in unselected presets.
- ui-agent-preset: the General-settings default-preset row is deleted — the
roster section's make-default and the new-session chip keep the field —
and the settings store slims to the display roster the header label reads.
Docs, catalogs, module graph, settings-chrome goldens, and the bilingual
Agent Note ride along.
* feat(ui-conversation): fold turn process before final answer
* fix(ui-chat): polish turn-process control row from review
* test(web): drive preset slash catalog with gestures
* fix(ui-chat): keep turn process order stable
* fix(ui-chat): preserve prompt order after pagination
Co-authored-by: Yif <877193178@qq.com>
The Agent Note (both languages), the PR prose, and the commit message
claimed a 13px floor for the table variants; the formula has none —
max(13px, setting − 2px) selects the −1 branch at low settings rather
than clamping the result, so the tier bottoms out at 11px at the 12px
setting, matching think text. Rewrite the claim, say so in the axis
comment, and split the README sentence that lumped body-pair and
secondary-pair consumers together.
Assert the engine-resolved secondary size in the settings-chrome e2e
(13px at the default, 13px at the 15px boundary, 14px at 16px,
unchanged across reload), sync the StatsLine and workflow-panel spec
headers with the tier they now pin, and note why memberLabel stays at
the body size.
The parity gate recognized only a `[['zh',{...}],['en',{...}]]` array, so the
two separate ctx.locale.register(NS, 'zh'|'en', {...}) calls in
ui-permission-presets were unchecked: deleting a key from one side left the
gate green. Pair those calls by their namespace argument. Widen the pre-filter
to admit zhSettings/accessZh spellings, which a bare \b(zh|en)\b misses and
would have skipped before parsing.
Assert document.documentElement.lang in the assembled app. The served markup
already ships lang="en", so the fr-FR scenario passes whether or not the sync
runs; the zh scenario is the discriminating half and now asserts zh-CN before
the switch and en after it.
Drop the dead vi.unstubAllGlobals() from the document-language spec, which
manages navigator with defineProperty and never calls vi.stubGlobal.
setLocale returned early when the id already matched the active locale, so
choosing the language already on screen wrote nothing. That value may be a
provisional browser-derived or fallback resolution nothing has stored, so a
different browser sharing the DSH home still resolved on its own. Write
unconditionally; keep the render publish conditional.
Broaden the dictionary parity gate to every workspace package, pair zh/en
across sibling files and inline registrations, and fail when a dictionary has
no counterpart. It previously scanned only packages/client and packages/
extensions, compared within a single module, and silently skipped unpaired
dictionaries -- so the split locales/zh.ts + en.ts common pair, the inline
directory-picker-browse dictionary, and session-log-export were unchecked.
Normalize paths at ingestion so the sweep does not narrow on Windows.
Regenerate the client API catalog and update the locale README pair: both
described the old zh fallback direction.
Add the English fallback dialog golden, and drop a dead afterEach plus the
blank lines left where the dead browser-language pins were removed.
The provisional locale fell back to zh, so a browser asking for neither
zh nor en (fr, de) opened the product in Chinese. Resolve to en instead,
and use en as the dictionary fallback: the shipped zh/en dictionaries
declare identical key sets, so one constant serves both roles.
Add scripts/locale-dictionary-parity.spec.ts to gate that symmetry, and
set the asserted locale explicitly in specs that had relied on the old
zh fallback through a dead usePinnedBrowserLanguages call (those files
declare no jsdom environment, so browser detection never ran there).
Delete design-session citations (decision/audit/plan ordinals, stack
positions), change narration, review choreography, and reviewer-addressed
justification from comments, JSDoc, docs, READMEs, Agent Notes, tests, and
generator templates; restate every affected fact as current-state contract
prose. Fix generated docs at their sources and regenerate the catalogs and
cordis-surface regions; re-paste type-equiv blocks; update every bilingual
counterpart and re-record the pairs. Record the citation rule in the
committed-artifact-citations Agent Note.
Node >= 21 exposes a global `navigator` reporting the machine's own language,
so gating detection on `navigator` let a non-browser boot of the client tree
resolve to `en` instead of the documented fallback; `window` is the browser
test. `navigator.languages` is spec-required but absent on some embedders and
older WebViews, where spreading it would throw at boot, so the walk tolerates
its absence and `navigator.language` covers that host.
The per-spec pin boilerplate collapses into one suite-level
`usePinnedBrowserLanguages('zh-CN')`, which owns the rationale in
dsh-client-test-runtime, and the English-browser e2e scenario now clears the
console warnings channel too — its page has no closing inventory spec.
A first visit resolved to Chinese regardless of the browser: LocaleService
read `dsh.locale` and fell straight back to `zh` when nothing was stored,
ignoring the languages the browser already states it reads.
The initial locale now resolves through three ordered sources — the persisted
preference, then `navigator` (first entry of the ordered language list whose
primary subtag names a shipped locale, so `zh-Hans-CN` -> zh and `en-GB` ->
en), then `FALLBACK_LOCALE`. An explicit choice still wins and nothing writes
the detected locale back to storage, so "has the user chosen?" stays a
question only the stored value answers.
Specs asserting the shipped Chinese copy now state the browser they assume:
the web e2e scenarios open their page with `locale: ZH_BROWSER_LOCALE`, and
package specs pin it through the new `pinBrowserLanguages` test helper.
`settings-chrome.e2e.ts` gains an English-browser scenario as the
assembled-app proof.