feat: integrate marketplace plugins with coding runtime

This commit is contained in:
brother7 committed 2026-08-28 18:08:33 +08:00
1 parent 1d64b89499
commit 05917a789a
21 files changed
+1921 -29

No files matched your search

@@ -28,6 +28,9 @@ import type { PiWorkerProcessOptions } from '../../electron/coding-runtime/pi/wo
import type { PiRuntimeTelemetryEvent } from '../../electron/coding-runtime/pi/telemetry';
import { PiManagedExtensionHost } from '../../electron/coding-runtime/pi/extension-host';
import { PiWorkerPool } from '../../electron/coding-runtime/pi/worker-pool';
import type { CodingCapabilityRegistry } from '../../electron/coding-plugins/registry';
import type { EffectivePluginSnapshot } from '../../electron/coding-plugins/effective-resolver';
import { DATA_SERVICE_PLUGIN_DEFINITION } from '../../shared/coding-plugins';
const roots: string[] = [];
const NOW = '2026-08-22T16:00:00.000Z';
@@ -128,6 +131,32 @@ describe('managed Pi worker opener', () => {
const telemetry: PiRuntimeTelemetryEvent[] = [];
const registry = new PiSessionRegistry({ projectStore });
const extensionHost = new PiManagedExtensionHost();
const effectiveSnapshot: EffectivePluginSnapshot = Object.freeze({
accountSessionId: 'account-a\u00001',
projectId: 'project-a',
pluginReleaseIds: Object.freeze(['plugin-release-a']),
effectiveSkillIds: Object.freeze(['grilling']),
skillEntries: Object.freeze([{ id: 'grilling', entryPath: 'grilling/SKILL.md' }]),
toolDefinitions: Object.freeze(DATA_SERVICE_PLUGIN_DEFINITION.tools),
runtimePolicies: Object.freeze([]),
unavailableReasons: Object.freeze([]),
});
const capabilityRegistry = {
resolveWorkerResources: vi.fn(async () => ({
catalogRevision: 1,
pluginIds: [],
effectiveSkillIds: ['grilling'],
skillEntries: [{ id: 'grilling', entryPath: 'grilling/SKILL.md' }],
tools: DATA_SERVICE_PLUGIN_DEFINITION.tools,
effectiveSnapshot,
})),
} as unknown as CodingCapabilityRegistry;
const releaseCleanups: Array<ReturnType<typeof vi.fn>> = [];
const registerActivePluginReleases = vi.fn((_releaseIds: readonly string[]) => {
const cleanup = vi.fn();
releaseCleanups.push(cleanup);
return cleanup;
});
const createOpener = (
openerRegistry: PiSessionRegistry,
createSessionKey: () => string = () => 'session-key-a',
@@ -138,6 +167,8 @@ describe('managed Pi worker opener', () => {
userDataDir,
bundledSkillsDir: path.resolve('resources/coding-skills'),
extensionHost,
capabilityRegistry,
registerActivePluginReleases,
loadProviderInput: async () => ({ accounts: [account], modelSummaries: [] }),
resolveCredential: async () => 'provider-secret-value',
createSessionKey,
@@ -194,6 +225,15 @@ describe('managed Pi worker opener', () => {
expect(options.sensitiveValues).toContain('provider-secret-value');
expect(options.env?.MAKELORE_PI_BRIDGE_URL).toMatch(/^http:\/\/127\.0\.0\.1:/);
expect(options.env?.MAKELORE_PI_CONTEXT_FILE).toContain('worker-');
expect(options.tools?.filter((name) => name.startsWith('data_service_')))
.toEqual(effectiveSnapshot.toolDefinitions.map(({ name }) => name));
const workerContext = JSON.parse(await readFile(
options.env?.MAKELORE_PI_CONTEXT_FILE as string,
'utf8',
)) as Record<string, unknown>;
expect(workerContext.effectivePluginSnapshot).toEqual(effectiveSnapshot);
expect(workerContext.allowedToolNames)
.toEqual(effectiveSnapshot.toolDefinitions.map(({ name }) => name));
}
const modelsFile = path.join(userDataDir, 'coding-runtime', 'pi', 'config', 'models.json');
expect(await readFile(modelsFile, 'utf8')).not.toContain('provider-secret-value');
@@ -210,9 +250,13 @@ describe('managed Pi worker opener', () => {
expect(first.worker.delayNextResponseForProof).toBeTypeOf('function');
first.worker.delayNextResponseForProof?.('prompt', 12_000);
expect(processes[0]?.proofResponseDelays).toEqual([{ commandType: 'prompt', delayMs: 12_000 }]);
expect(registerActivePluginReleases).toHaveBeenCalledTimes(3);
expect(registerActivePluginReleases).toHaveBeenNthCalledWith(1, ['plugin-release-a']);
await first.worker.stop('test_injection');
await reopened.worker.stop('test_injection');
await restarted.worker.stop('test_injection');
expect(releaseCleanups).toHaveLength(3);
expect(releaseCleanups.every((cleanup) => cleanup.mock.calls.length === 1)).toBe(true);
await extensionHost.close();
});