fix(marketplace): preserve release sync semantics
This commit is contained in:
@@ -205,7 +205,10 @@ describe('effective plugin resolver', () => {
|
||||
{ id: 'shared-skill', entryPath: 'skills/shared/SKILL.md', packageRoot: 'C:/packages/collision-a-1' },
|
||||
]);
|
||||
expect(result.pluginReleaseIds).toEqual(['collision-a-1']);
|
||||
expect(result.unavailableReasons).toEqual([]);
|
||||
expect(result.unavailableReasons).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ pluginId: coreCollision.id, code: 'skill_owner_conflict' }),
|
||||
expect.objectContaining({ pluginId: packageB.id, code: 'skill_owner_conflict' }),
|
||||
]));
|
||||
});
|
||||
|
||||
it('reserves every bundled Skill owner, including Data Service, before accepting Marketplace packages', async () => {
|
||||
@@ -238,9 +241,10 @@ describe('effective plugin resolver', () => {
|
||||
});
|
||||
|
||||
expect(result.pluginReleaseIds).toEqual([]);
|
||||
expect(result.unavailableReasons).not.toEqual([
|
||||
expect.objectContaining({ pluginId: marketplaceDataServiceCollision.id }),
|
||||
]);
|
||||
expect(result.unavailableReasons).toContainEqual(expect.objectContaining({
|
||||
pluginId: marketplaceDataServiceCollision.id,
|
||||
code: 'skill_owner_conflict',
|
||||
}));
|
||||
});
|
||||
|
||||
it('requires current Library, installed Release, project selection, and assignment', async () => {
|
||||
@@ -284,6 +288,40 @@ describe('effective plugin resolver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps installed skill-only local under a trusted stale Library while hosted stays fail-closed', async () => {
|
||||
const staleNotesLibrary = { ...library(), stale: true };
|
||||
await expect(resolve(resolver({ getLibrary: vi.fn(async () => staleNotesLibrary) })))
|
||||
.resolves.toMatchObject({
|
||||
effectiveSkillIds: ['notes'],
|
||||
pluginReleaseIds: ['notes-1'],
|
||||
unavailableReasons: [],
|
||||
});
|
||||
|
||||
const staleHostedLibrary = {
|
||||
...library(),
|
||||
stale: true,
|
||||
items: [{ ...library().items[0], pluginId: serverDefinition.id }],
|
||||
};
|
||||
const hosted = createEffectivePluginResolver({
|
||||
definitions: [serverDefinition],
|
||||
getAccountBinding: () => binding,
|
||||
getLibrary: vi.fn(async () => staleHostedLibrary),
|
||||
getInstalled: vi.fn(async () => installed(serverDefinition)),
|
||||
getEnabledPluginIds: vi.fn(async () => [serverDefinition.id]),
|
||||
policyClient: { getState: currentPolicy, refresh: vi.fn() },
|
||||
});
|
||||
await expect(hosted.resolve({
|
||||
projectId: 'project-a', projectPath: 'C:/project-a', assignedSkillIds: ['remote'], role: 'parent',
|
||||
})).resolves.toMatchObject({
|
||||
effectiveSkillIds: [],
|
||||
pluginReleaseIds: [],
|
||||
unavailableReasons: [expect.objectContaining({
|
||||
pluginId: serverDefinition.id,
|
||||
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