chore(gen1): 第一代版本封板 — DSH 2.0.17 兼容 + settings API 迁移 + React #130 修复

- peerDeps 升级到 0.2.0-rc.2
- settings API 迁移: register() → describe() + settings/document-updated
- turnTail slots.register 补 id 字段
- EditorHost viewer.component undefined guard
- 56/56 测试全绿, typecheck/build 通过

tag: v1.2.0-gen1
This commit is contained in:
figmar
2026-10-11 16:52:48 +08:00
parent df6f99c4a3
commit 0aafa94c4d
6 changed files with 484 additions and 258 deletions
+28 -13
View File
@@ -799,22 +799,28 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
}
}
ctx.inject(['settings'], (sctx) => {
// DSH 0.1.2-alpha.2 validates namespaces at compile time
// (SettingsNamespaceInput); the 'dsh-apes-sidebar' literal passes, so the
// runtime helper this used to call (settingsNamespace) is gone upstream.
const ns = SIDEBAR_PREFS_NS
// The structural settings mirror types `schema` as unknown, so the
// generic is not inferred here; the real service resolves it from the
// schemastery schema (PrefsSchema) — narrow the owner scope explicitly.
const scope = sctx.settings.register(ns, PrefsSchema) as {
get(): SidebarPrefs
watch(callback: (next: SidebarPrefs, prev: SidebarPrefs) => void): () => void
// 0.2.0-rc.2: `settings.register()` is gone. The plugin's Config schema
// (config.ts → Config) is auto-registered by the loader under ns =
// entry.options.id (= package name). We read it through describe() and
// watch for changes via the `settings/document-updated` event.
const readPrefs = (): SidebarPrefs => {
const descriptor = sctx.settings.describe({ redactSecrets: true }).find(c => c.ns === ns)
const raw = descriptor?.value as Record<string, unknown> | undefined
return raw !== null && typeof raw === 'object'
? raw as unknown as SidebarPrefs
: SIDEBAR_PREFS_DEFAULTS
}
const scope = { get: readPrefs }
const viewOf = (): { value?: unknown; revision?: number } => {
const descriptor = sctx.settings.describe({ redactSecrets: true }).find(candidate => candidate.ns === ns)
return descriptor === undefined
? { value: undefined, revision: undefined }
: { value: descriptor.value, revision: descriptor.revision }
if (descriptor === undefined) return { value: undefined, revision: undefined }
// 0.2.0-rc.2: describe() may return value=undefined for a namespace that
// has no user-set document yet (the Config schema defaults are applied
// lazily). Fall back to the schema defaults so the client always gets a
// well-formed object (React #130 guard).
const value = descriptor.value ?? SIDEBAR_PREFS_DEFAULTS
return { value, revision: descriptor.revision }
}
// Mutual exclusion with the dsh-web-ui family right panel: the aionui
// panel's provider choice (`aionui-panel.rightPanel`) is the authority.
@@ -869,7 +875,12 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
// ONE watch subscription drives both gates: settings commits re-evaluate
// the terminal tools AND the open tool together (each gate is idempotent
// and owns its own disposer).
scope.watch(() => { syncToolsGate(scope); syncOpenToolsGate() })
// 0.2.0-rc.2: `scope.watch()` is gone; use the `settings/document-updated`
// event emitted on the plugin context (ownerContext) by the SettingsForms
// service on every describe() call that detects a raw-value change.
ctx.on('settings/document-updated', (changedNs: string) => {
if (changedNs === ns) { syncToolsGate(scope); syncOpenToolsGate() }
})
})
// ── JSON API ────────────────────────────────────────────────────────────
@@ -880,6 +891,10 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
// effect releases the listener on fiber disposal.
const assistantLive = createAssistantLiveBuffer(ctx)
ctx.effect(() => () => { assistantLive.dispose() }, 'dsh-apes-sidebar: live assistant stream buffer')
// NOTE: `buildApi` must come AFTER `ctx.inject(['settings'], ...)` so the
// closure captures the settingsFace value set inside the inject callback.
// 0.2.0-rc.2 removed `settings.register()`; settingsFace is now populated
// synchronously during inject, not lazily at first call.
const api = buildApi(ctx, ptyManager, agentPtyRegistry, resolved, terminalShell, () => settingsFace, assistantLive)
ctx.effect(() => ctx.webServer.register({
kind: 'prefix',