fix(plugins): preserve frozen hosted workers on stale library
This commit is contained in:
@@ -273,6 +273,7 @@ describe('CodingCapabilityRegistry', () => {
|
||||
const resolve = vi.fn(async () => frozenSnapshot);
|
||||
const effectiveResolver = {
|
||||
resolve,
|
||||
resolveForInvocation: resolve,
|
||||
getSkillSources: vi.fn(async () => []),
|
||||
getPolicyState: vi.fn(() => hostedPolicy),
|
||||
getInstalledDefinition: vi.fn(async () => hostedDefinition),
|
||||
@@ -400,8 +401,10 @@ describe('CodingCapabilityRegistry', () => {
|
||||
const resolve = vi.fn(async ({ role }: { role: 'parent' | 'child' }) => (
|
||||
role === 'child' ? { ...disabled, unavailableReasons: [] } : current
|
||||
));
|
||||
const resolveForInvocation = vi.fn(async () => current);
|
||||
const effectiveResolver = {
|
||||
resolve,
|
||||
resolveForInvocation,
|
||||
getSkillSources: vi.fn(async () => [{
|
||||
id: 'web-search', pluginId: definition.id, packageRoot: 'C:/packages/web-search',
|
||||
directory: 'C:/packages/web-search/skills/web-search', entryPath: 'SKILL.md',
|
||||
@@ -461,6 +464,7 @@ describe('CodingCapabilityRegistry', () => {
|
||||
capability_id: 'web-search.search', operation: 'search',
|
||||
payload_schema: 'web-search.v1', billing: { status: 'settled', actual_points: '1.00' },
|
||||
});
|
||||
expect(resolveForInvocation).toHaveBeenCalledOnce();
|
||||
|
||||
current = disabled;
|
||||
const stale = await capabilityRegistry.invoke({
|
||||
@@ -497,6 +501,7 @@ describe('CodingCapabilityRegistry', () => {
|
||||
};
|
||||
const effectiveResolver = {
|
||||
resolve: vi.fn(async () => currentSnapshot),
|
||||
resolveForInvocation: vi.fn(async () => currentSnapshot),
|
||||
getSkillSources: vi.fn(async () => []),
|
||||
getPolicyState: vi.fn(() => policy),
|
||||
} as unknown as EffectivePluginResolver;
|
||||
@@ -509,7 +514,7 @@ describe('CodingCapabilityRegistry', () => {
|
||||
});
|
||||
|
||||
expect(result.details).toMatchObject({ success: false, code: 'plugin_not_enabled' });
|
||||
expect(effectiveResolver.resolve).toHaveBeenCalledWith(expect.objectContaining({
|
||||
expect(effectiveResolver.resolveForInvocation).toHaveBeenCalledWith(expect.objectContaining({
|
||||
projectId: context.projectId,
|
||||
projectPath: context.projectPath,
|
||||
role: 'parent',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user