feat(web-search): wire hosted plugin composition

This commit is contained in:
2026-09-01 02:39:16 +08:00
parent 68cb2e73be
commit 60e6a8eeb3
9 changed files with 361 additions and 6 deletions

View File

@@ -4,21 +4,69 @@ import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it, vi } from 'vitest';
import type { AgentBrowserModule } from '../../electron/agent-browser';
import { createCodingComposition } from '../../electron/api/coding-composition';
import {
createCodingProjectPluginService,
} from '../../electron/api/coding-product-services';
import { createCodingProjectMetadata, createCodingProjectAgent } from '../../electron/coding-projects/project-config';
import type { CodingPluginAdapter } from '../../electron/coding-plugins/registry';
import { createProjectPluginService } from '../../electron/coding-plugins/project-service';
import { createMemoryCodingProjectStorage } from '../../electron/coding-projects/project-store';
import { DATA_SERVICE_PLUGIN_DEFINITION } from '../../shared/coding-plugins';
const webSearchAdapterMock = vi.hoisted(() => ({
create: vi.fn(),
deactivate: vi.fn().mockResolvedValue(undefined),
}));
vi.mock('../../electron/coding-plugins/adapters/web-search', () => ({
createWebSearchPluginAdapter: webSearchAdapterMock.create.mockImplementation(() => ({
pluginId: 'makelore.web-search',
inspect: vi.fn().mockResolvedValue({ status: 'ready' }),
invoke: vi.fn(),
deactivate: webSearchAdapterMock.deactivate,
})),
}));
const roots: string[] = [];
afterEach(async () => {
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
webSearchAdapterMock.create.mockClear();
webSearchAdapterMock.deactivate.mockClear();
});
describe('coding plugin bounded product service', () => {
it('registers the code-owned Web Search adapter in the production composition', async () => {
const projectPath = await mkdtemp(path.join(tmpdir(), 'makelore-web-search-composition-project-'));
const userDataDir = await mkdtemp(path.join(tmpdir(), 'makelore-web-search-composition-user-'));
roots.push(projectPath, userDataDir);
const composition = createCodingComposition({
storage: createMemoryCodingProjectStorage(),
browser: { close: vi.fn().mockResolvedValue(undefined) } as unknown as AgentBrowserModule,
paths: {
executablePath: process.execPath,
cliPath: path.join(projectPath, 'unused-cli.js'),
serverPath: path.join(projectPath, 'unused-server.mjs'),
userDataDir,
bundledSkillsDir: path.resolve('resources/coding-skills'),
},
});
await composition.plugins.deactivate(projectPath, 'makelore.web-search');
expect(webSearchAdapterMock.create).toHaveBeenCalledOnce();
expect(webSearchAdapterMock.create).toHaveBeenCalledWith(expect.objectContaining({
client: expect.any(Object),
marketplace: expect.any(Object),
packageStore: expect.any(Object),
makeloreVersion: '2.0.0',
}));
expect(webSearchAdapterMock.deactivate).toHaveBeenCalledWith(projectPath);
await composition.shutdown();
});
it('joins package and policy exactly while isolating adapter inspection failure', async () => {
const root = await mkdtemp(path.join(tmpdir(), 'makelore-plugin-product-'));
roots.push(root);