fix(sidebar): read betterSidebar via ctx.get() in all internal consumers
Under the DSH 0.1.1-rc.x web shell, the Cordis plugin loader registers the provided betterSidebar impl on a neighboring fiber that is not on the rendering fiber parent chain, so every direct ctx.betterSidebar read inside the plugin own tree throws cannot get property "betterSidebar" without inject and the panel dies inside RenderBoundary on page load (observed with 0.14.0 and 0.15.2 on npm-installed dsh 0.1.1-rc.2). This is the same failure class #135 fixed for the dsh-web-mobile path; declaring betterSidebar in the plugin own inject would deadlock the fiber (it waits for the service before running apply, but the service is only provided inside apply). ctx.get() resolves through the root reflect store and is unaffected by the fiber chain, so all 26 internal reads switch to it. External consumers keep using ctx.betterSidebar after injecting it, unchanged. Test mocks gain a matching get() shim.
This commit is contained in:
@@ -65,6 +65,7 @@ function mountSidebar(): MountedSidebar {
|
||||
locale: { subscribe: () => () => {}, getSnapshot: () => localeSnapshot },
|
||||
sessions: { list: { subscribe: () => () => {}, getSnapshot: () => sessionsSnapshot } },
|
||||
betterSidebar: service,
|
||||
get: (name: string) => name === 'betterSidebar' ? service : undefined,
|
||||
}
|
||||
const root: Root = createRoot(container)
|
||||
act(() => { root.render(createElement(Sidebar, { ctx: ctx as never, store })) })
|
||||
|
||||
@@ -40,6 +40,7 @@ function setup(): {
|
||||
const sessionsSnapshot = { byId: { 'editor-home-session': { cwd: '/tmp' } }, current: 'editor-home-session' }
|
||||
const ctx = {
|
||||
betterSidebar: service,
|
||||
get: (name: string) => name === 'betterSidebar' ? service : undefined,
|
||||
sessions: { list: { subscribe: () => () => {}, getSnapshot: () => sessionsSnapshot } },
|
||||
} as unknown as Context
|
||||
return { store, ctx, homeTab }
|
||||
|
||||
@@ -108,6 +108,9 @@ describe('open-path interception wiring', () => {
|
||||
},
|
||||
workspaces: funnel,
|
||||
betterSidebar: { openTab: (seed: unknown) => { opened.push(seed as Record<string, unknown>) } },
|
||||
get: (name: string) => name === 'betterSidebar'
|
||||
? { openTab: (seed: unknown) => { opened.push(seed as Record<string, unknown>) } }
|
||||
: undefined,
|
||||
} as unknown as Context
|
||||
const store = createSidebarStore()
|
||||
const original = ctx.workspaces.openPath
|
||||
|
||||
@@ -68,6 +68,7 @@ function mountSidebar(): MountedSidebar {
|
||||
locale: { subscribe: () => () => {}, getSnapshot: () => localeSnapshot },
|
||||
sessions: { list: { subscribe: () => () => {}, getSnapshot: () => sessionsSnapshot } },
|
||||
betterSidebar: service,
|
||||
get: (name: string) => name === 'betterSidebar' ? service : undefined,
|
||||
}
|
||||
const root: Root = createRoot(container)
|
||||
act(() => { root.render(createElement(Sidebar, { ctx: ctx as never, store })) })
|
||||
|
||||
@@ -75,13 +75,17 @@ const producedOwner = (paths: string[]): unknown => ({
|
||||
const emptyOwner = (): unknown => ({ nodes: [{ kind: 'assistant', seq: 1, turn: 1 }], seq: 1 })
|
||||
|
||||
/** The minimal client-context fake the registration (and its seats) touch. */
|
||||
const clientCtx = (slots: unknown): Context => ({
|
||||
slots,
|
||||
sessions: {
|
||||
list: { getSnapshot: () => ({ current: 's1', byId: { s1: { id: 's1', cwd: '/w', displayTitle: 's1' } } }) },
|
||||
},
|
||||
betterSidebar: { openTab: vi.fn() },
|
||||
} as unknown as Context)
|
||||
const clientCtx = (slots: unknown): Context => {
|
||||
const betterSidebar = { openTab: vi.fn() }
|
||||
return {
|
||||
slots,
|
||||
sessions: {
|
||||
list: { getSnapshot: () => ({ current: 's1', byId: { s1: { id: 's1', cwd: '/w', displayTitle: 's1' } } }) },
|
||||
},
|
||||
betterSidebar,
|
||||
get: (name: string) => name === 'betterSidebar' ? betterSidebar : undefined,
|
||||
} as unknown as Context
|
||||
}
|
||||
|
||||
describe('turn-tail interception registration (issue #15)', () => {
|
||||
it('registers through slots.inject and lands once the slot is already declared', () => {
|
||||
|
||||
Reference in New Issue
Block a user