diff --git a/apps/desktop/.storybook/main.ts b/apps/desktop/.storybook/main.ts index 8aa012a7dd..b1355ffd84 100644 --- a/apps/desktop/.storybook/main.ts +++ b/apps/desktop/.storybook/main.ts @@ -33,7 +33,11 @@ const STORYBOOK_NODE_CRYPTO_BOUNDARY = resolve( const config: StorybookConfig = { stories: [ '../../../packages/ui/stories/**/*.stories.@(ts|tsx)', - resolve(REPO_ROOT, 'apps/desktop/stories/**/*.stories.@(ts|tsx)'), + // Config-relative glob (forward slashes) like the UI entry above. A + // `resolve(REPO_ROOT, ...)` absolute path produces backslashes on Windows, + // which glob matchers treat as escape characters, so no desktop story ever + // matches there. + '../stories/**/*.stories.@(ts|tsx)', ], framework: { name: '@storybook/react-vite', diff --git a/apps/desktop/src/main/__tests__/runtime-host-turn-request-inbox-preload.test.ts b/apps/desktop/src/main/__tests__/runtime-host-turn-request-inbox-preload.test.ts index 267504c866..b188c23f6a 100644 --- a/apps/desktop/src/main/__tests__/runtime-host-turn-request-inbox-preload.test.ts +++ b/apps/desktop/src/main/__tests__/runtime-host-turn-request-inbox-preload.test.ts @@ -38,12 +38,16 @@ test('keeps available collaboration inboxes when another Owner Host rejects', as assert.deepEqual(requests.map(({ requestId }) => requestId), ['earlier', 'later']); }); -test('retains the previous inbox projection when every Owner Host rejects', async () => { - await assert.rejects( - collectAvailablePendingTurnRequests([ - Promise.reject(new Error('first unavailable')), - Promise.reject(new Error('second unavailable')), - ]), - /Every Runtime Host collaboration inbox request failed/, - ); +test('returns an empty inbox when every Owner Host rejects', async () => { + // A Host without a collaboration authority (e.g. the default Local Host) + // rejects each query with `operation_unavailable`. That is a valid + // composition, not an error, so the inbox resolves empty rather than + // throwing — the poller keeps the quiet, empty inbox instead of logging an + // IPC failure every interval. + const requests = await collectAvailablePendingTurnRequests([ + Promise.reject(new Error('first unavailable')), + Promise.reject(new Error('second unavailable')), + ]); + + assert.deepEqual(requests, []); }); diff --git a/apps/desktop/src/preload/runtime-host-turn-request-inbox.ts b/apps/desktop/src/preload/runtime-host-turn-request-inbox.ts index 86199b9187..6da5ed1667 100644 --- a/apps/desktop/src/preload/runtime-host-turn-request-inbox.ts +++ b/apps/desktop/src/preload/runtime-host-turn-request-inbox.ts @@ -26,12 +26,11 @@ export async function collectAvailablePendingTurnRequests( const available = results.flatMap( (result) => result.status === 'fulfilled' ? [result.value] : [], ); - if (queries.length > 0 && available.length === 0) { - throw new AggregateError( - results.flatMap((result) => result.status === 'rejected' ? [result.reason] : []), - 'Every Runtime Host collaboration inbox request failed', - ); - } + // A Host with no collaboration authority rejects every inbox query with + // `operation_unavailable`. That is a valid composition (e.g. the default + // Local Host), not a failure, so when no Host answered we surface an empty + // inbox instead of throwing — the next poll repopulates it once a capable + // Host appears. return available .flat() .sort((left, right) => left.createdAt.localeCompare(right.createdAt));