Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions apps/desktop/src/main/__tests__/ipc-surface-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ const desktopRoot = process.cwd().endsWith(join('apps', 'desktop'))
? process.cwd()
: join(process.cwd(), 'apps', 'desktop');

// Temporary Main-only Usage/Pricing routes; coordinate Host replacement in #2010 and #2015.
const RETAINED_MAIN_ONLY_CHANNELS = new Set([
'usage:summary',
'usage:buckets',
'usage:logs',
'usage:pricing:list',
'usage:pricing:put',
'usage:pricing:reset',
]);

async function findTypeScriptFiles(directory: string): Promise<string[]> {
const entries = await readdir(directory, { withFileTypes: true });
const files = await Promise.all(
Expand All @@ -27,7 +37,7 @@ function extractChannels(source: string, pattern: RegExp): Set<string> {
}

describe('IPC surface contract', () => {
it('keeps main handlers and preload invocations in parity', async () => {
it('keeps preload parity except for the retained Usage authority handlers', async () => {
const mainFiles = await findTypeScriptFiles(join(desktopRoot, 'src', 'main'));
const [mainSources, preloadSource] = await Promise.all([
Promise.all(mainFiles.map((file) => readFile(file, 'utf8'))),
Expand All @@ -42,6 +52,22 @@ describe('IPC surface contract', () => {
/ipcRenderer\.invoke\(\s*['"]([^'"]+)['"]/g,
);

assert.deepEqual([...mainChannels].sort(), [...preloadChannels].sort());
const retainedMainChannels = new Set(
[...mainChannels].filter((channel) => RETAINED_MAIN_ONLY_CHANNELS.has(channel)),
);
const exposedMainChannels = new Set(
[...mainChannels].filter((channel) => !RETAINED_MAIN_ONLY_CHANNELS.has(channel)),
);

assert.deepEqual(
[...retainedMainChannels].sort(),
[...RETAINED_MAIN_ONLY_CHANNELS].sort(),
'every approved Main-only Usage handler must remain registered',
);
assert.deepEqual(
[...exposedMainChannels].sort(),
[...preloadChannels].sort(),
'all other Main handlers and preload invocations must stay in exact parity',
);
});
});
16 changes: 0 additions & 16 deletions apps/desktop/src/preload/bridge-contract.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ import type {
DeepResearchRun,
LocalMemoryEntryPreview,
} from '@maka/core';
import type {
PricingConfig,
UsageBucket,
UsageGroupBy,
UsageLogRow,
UsageQuery,
UsageSummaryV2,
} from '@maka/core/usage-stats/types';
import type { SessionTrace } from '@maka/core/session-trace';
import type { TestProxyInput } from '@maka/core/settings/network-settings';
import type { Result } from '@maka/core/result';
Expand Down Expand Up @@ -587,14 +579,6 @@ export interface MakaBridge {
/** Read-only per-session causal trace (#1625). */
trace(sessionId: string): Promise<Result<SessionTrace>>;
};
usage: {
summary(query: UsageQuery): Promise<Result<UsageSummaryV2>>;
buckets(query: UsageQuery & { groupBy: UsageGroupBy }): Promise<Result<UsageBucket[]>>;
logs(query: UsageQuery & { offset?: number; limit?: number }): Promise<Result<{ rows: UsageLogRow[]; total: number }>>;
listPricing(): Promise<Result<PricingConfig[]>>;
putPricing(pricing: PricingConfig): Promise<Result<PricingConfig>>;
resetPricing(modelKey: string): Promise<Result<void>>;
};
webSearch: {
query(input: {
query: string;
Expand Down
28 changes: 0 additions & 28 deletions apps/desktop/src/preload/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,6 @@ import type {
DeepResearchChangedEvent,
DeepResearchRun,
} from '@maka/core';
import type {
PricingConfig,
UsageBucket,
UsageGroupBy,
UsageLogRow,
UsageQuery,
UsageSummaryV2,
} from '@maka/core/usage-stats/types';
import type { SessionTrace } from '@maka/core/session-trace';
import type {
AgentGraphClientChangedEvent,
Expand Down Expand Up @@ -909,26 +901,6 @@ const makaBridge = {
return ipcRenderer.invoke('inspector:trace', sessionId);
},
},
usage: {
summary(query: UsageQuery): Promise<Result<UsageSummaryV2>> {
return ipcRenderer.invoke('usage:summary', query);
},
buckets(query: UsageQuery & { groupBy: UsageGroupBy }): Promise<Result<UsageBucket[]>> {
return ipcRenderer.invoke('usage:buckets', query);
},
logs(query: UsageQuery & { offset?: number; limit?: number }): Promise<Result<{ rows: UsageLogRow[]; total: number }>> {
return ipcRenderer.invoke('usage:logs', query);
},
listPricing(): Promise<Result<PricingConfig[]>> {
return ipcRenderer.invoke('usage:pricing:list');
},
putPricing(pricing: PricingConfig): Promise<Result<PricingConfig>> {
return ipcRenderer.invoke('usage:pricing:put', pricing);
},
resetPricing(modelKey: string): Promise<Result<void>> {
return ipcRenderer.invoke('usage:pricing:reset', modelKey);
},
},
dailyReview: {
day(offsetDays: number, daySpan?: number): Promise<Result<DailyReviewSummary>> {
return ipcRenderer.invoke('daily-review:day', { offsetDays, daySpan });
Expand Down
Loading