fix(plugins): preserve frozen hosted workers on stale library

This commit is contained in:
2026-09-01 22:26:20 +08:00
parent 697c68974d
commit 40e1912f2f
5 changed files with 217 additions and 3 deletions

View File

@@ -322,6 +322,44 @@ describe('effective plugin resolver', () => {
});
});
it('keeps a frozen hosted worker usable through a transient stale Library refresh', async () => {
const currentHostedLibrary = {
...library(),
items: [{ ...library().items[0], pluginId: serverDefinition.id }],
};
const getLibrary = vi.fn()
.mockResolvedValueOnce(currentHostedLibrary)
.mockResolvedValue({ ...currentHostedLibrary, stale: true });
const hosted = createEffectivePluginResolver({
definitions: [serverDefinition],
getAccountBinding: () => binding,
getLibrary,
getInstalled: vi.fn(async () => installed(serverDefinition)),
getEnabledPluginIds: vi.fn(async () => [serverDefinition.id]),
policyClient: { getState: currentPolicy, refresh: vi.fn() },
});
const input = {
projectId: 'project-a', projectPath: 'C:/project-a',
assignedSkillIds: ['remote'], role: 'parent' as const,
};
const frozen = await hosted.resolve(input);
expect(frozen.toolDefinitions).toEqual([expect.objectContaining({ name: 'remote_read' })]);
await expect(hosted.resolveForInvocation(input)).resolves.toMatchObject({
accountSessionId: frozen.accountSessionId,
pluginReleaseIds: frozen.pluginReleaseIds,
toolDefinitions: [{ name: 'remote_read' }],
runtimePolicies: [{ pluginId: serverDefinition.id, operation: 'read' }],
unavailableReasons: [],
});
await expect(hosted.resolve(input)).resolves.toMatchObject({
toolDefinitions: [],
runtimePolicies: [],
unavailableReasons: [expect.objectContaining({ code: 'library_unavailable' })],
});
});
it('never exposes plugin resources to a child worker', async () => {
const result = await resolver().resolve({
projectId: 'project-a', projectPath: 'C:/project-a', assignedSkillIds: ['notes'], role: 'child',