fix(web): persist general preferences in host settings

This commit is contained in:
Yichen Jiang
2026-08-07 16:43:59 +08:00
parent fcc3148cc9
commit 0833b29f25
78 changed files with 1153 additions and 615 deletions

View File

@@ -308,8 +308,8 @@ describe('settings domain', () => {
// The settings seam is general: any plugin may register a namespace for
// its own configuration. The Web configuration plane remains opt-in, so a
// future internal plugin cannot become remotely configurable just by
// registering; permission, theme, and the product onboarding namespace
// are the non-model namespaces intentionally admitted by this surface.
// registering; locale, permission, conversation, theme, and the product
// onboarding namespace are intentionally admitted by this surface.
const ctx = await harness()
ctx.settings.register(NS, AdapterConfig)
ctx.settings.register(settingsNamespace('some-other-plugin'), z.object({ secretPath: z.string() }))
@@ -321,10 +321,18 @@ describe('settings domain', () => {
ctx.settings.register(settingsNamespace('ui-theme'), z.object({
preference: z.union(['light', 'dark', 'system']).default('system'),
}))
ctx.settings.register(settingsNamespace('locale'), z.object({
preference: z.union(['zh', 'en']).required(false),
}))
ctx.settings.register(settingsNamespace('ui-conversation'), z.object({
busyEnter: z.union(['queue', 'steer']).default('queue'),
}))
const api = createApiProxy(ctx, DEFAULTS)
const value = expectOk(await api.settings.describe(request({})))
expect(value.namespaces.map(view => view.ns)).toEqual(['llm-deepseek', 'permission', 'ui-theme'])
expect(value.namespaces.map(view => view.ns)).toEqual([
'llm-deepseek', 'permission', 'ui-theme', 'locale', 'ui-conversation',
])
const permission = expectOk(await api.settings.mutate(request({
ns: 'permission',
ops: [{ op: 'set', path: ['defaultPreset'], value: 'workspace-write' }],
@@ -335,6 +343,16 @@ describe('settings domain', () => {
ops: [{ op: 'set', path: ['preference'], value: 'dark' }],
})))
expect(theme.value).toEqual({ preference: 'dark' })
const locale = expectOk(await api.settings.mutate(request({
ns: 'locale',
ops: [{ op: 'set', path: ['preference'], value: 'en' }],
})))
expect(locale.value).toEqual({ preference: 'en' })
const conversation = expectOk(await api.settings.mutate(request({
ns: 'ui-conversation',
ops: [{ op: 'set', path: ['busyEnter'], value: 'steer' }],
})))
expect(conversation.value).toEqual({ busyEnter: 'steer' })
for (const response of [
await api.settings.update(request({ ns: 'some-other-plugin', patch: { secretPath: '/etc/shadow' } })),