feat(plugins): merge Skill management into plugins

This commit is contained in:
inman
2026-09-07 18:36:33 +08:00
parent bb8a19eecf
commit ab9f889233
49 changed files with 461 additions and 1218 deletions

View File

@@ -129,7 +129,7 @@ function devicePackage(packageId: string, displayName: string, enabled: boolean)
resolvedVersion: '1.0.0',
source: { kind: 'npm', requested: packageId, resolved: `${packageId}@1.0.0` },
kind: 'skill-only',
skillEntries: [],
skillEntries: [{ id: `${packageId}.skill`, entryPath: 'SKILL.md' }],
extensionEntries: [],
enabled,
confirmedExecutableCode: false,
@@ -138,6 +138,45 @@ function devicePackage(packageId: string, displayName: string, enabled: boolean)
}
describe('buildPluginWorkspaceProjection', () => {
it('places a user-installed loose Skill only in the installed tab', () => {
const looseSkill = {
...devicePackage('local-writing', 'Local Writing', true),
source: {
kind: 'file' as const,
requested: '/Users/example/.codex/skills/local-writing/SKILL.md',
resolved: '/Users/example/.codex/skills/local-writing/SKILL.md',
},
};
const base = {
catalog: null,
library: null,
marketplaceInstallations: {},
project: null,
activeProject: null,
devicePackages: { schemaVersion: 1 as const, generation: 2, packages: [looseSkill] },
};
const installed = buildPluginWorkspaceProjection(input({
...base,
filters: { scope: 'all', source: 'all', state: 'mine', search: '' },
}));
expect(installed.items).toEqual([
expect.objectContaining({
key: 'local:local-writing',
source: 'local',
delivery: 'local_installed',
local: expect.objectContaining({ kind: 'skill-only' }),
}),
]);
expect(installed.counts).toMatchObject({ available: 0, mine: 1 });
const available = buildPluginWorkspaceProjection(input({
...base,
filters: { scope: 'all', source: 'all', state: 'available', search: '' },
}));
expect(available.items).toEqual([]);
});
it('merges every official source into one item with only its legal commands', () => {
const result = buildPluginWorkspaceProjection(input());
@@ -562,11 +601,11 @@ describe('buildPluginWorkspaceProjection', () => {
}));
const all = projectAll({ scope: 'all', source: 'all', state: 'all', search: '' });
expect(all.counts).toEqual({ all: 6, available: 1, mine: 3, enabled: 2, update: 1, unavailable: 2 });
expect(all.counts).toEqual({ all: 6, available: 2, mine: 4, enabled: 2, update: 1, unavailable: 2 });
const expectedByState = {
available: ['official:makelore.available'],
mine: ['official:makelore.notes', 'local:alpha.package', 'local:zeta.package'],
available: ['official:makelore.available', 'official:makelore.suspended'],
mine: ['official:makelore.notes', 'local:alpha.package', 'local:zeta.package', 'retained:makelore.ghost'],
enabled: ['official:makelore.notes', 'local:alpha.package'],
update: ['official:makelore.notes'],
unavailable: ['official:makelore.suspended', 'retained:makelore.ghost'],