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

@@ -5,7 +5,6 @@ import type {
} from '../../shared/coding-plugins';
import { isProjectWideCodingPluginId } from '../../shared/coding-plugins';
import {
CORE_CODING_SKILL_IDS,
type CodingSkillId,
} from '../../shared/coding-skills';
import {
@@ -218,13 +217,13 @@ function validateBinding(value: AccountBinding | null): AccountBinding | null {
}
/**
* A raw Skill ID is the public assignment key. Marketplace packages cannot
* shadow a core Skill or an already accepted package owner; the project
* A raw Skill ID is the public assignment key. Marketplace packages cannot
* shadow a code-owned plugin Skill or an already accepted package owner; the project
* assignment is retained, but the later package contributes no resources.
*/
function marketplaceSkillConflicts(records: readonly DefinitionRecord[]): ReadonlySet<string> {
const blocked = new Set<string>();
const owned = new Set<string>(CORE_CODING_SKILL_IDS);
const owned = new Set<string>();
for (const { definition } of records) {
if (definition.provenance.source === 'marketplace') continue;
for (const { id } of definition.skills) owned.add(id);
@@ -282,19 +281,14 @@ export class EffectivePluginResolver {
const blockedMarketplacePlugins = marketplaceSkillConflicts(definitions);
const assigned = normalizeIds(input.assignedSkillIds);
const coreIds = new Set<string>(CORE_CODING_SKILL_IDS);
const effectiveSkillIds: CodingSkillId[] = assigned.filter((id) => coreIds.has(id));
const skillEntries: SkillEntry[] = effectiveSkillIds.map((id) => ({
id,
entryPath: `${id}/SKILL.md`,
}));
const effectiveSkillIds: CodingSkillId[] = [];
const skillEntries: SkillEntry[] = [];
const pluginReleaseIds: string[] = [];
const toolDefinitions: CodingPluginToolDefinition[] = [];
const runtimePolicies: RuntimePolicy[] = [];
const unavailableReasons: PluginUnavailableReason[] = [];
// Child workers intentionally receive only core resources. Still validate
// assignment IDs above so malformed project configuration remains visible.
// Child workers intentionally receive no plugin-delivered Skill resources.
if (input.role === 'child') {
return freezeSnapshot({
accountSessionId: accountSessionId(this.options, validateBinding(this.options.getAccountBinding?.() ?? null)),

View File

@@ -3,7 +3,6 @@ import {
type CodingPluginToolDefinition,
type PluginBillingMode,
} from '../../shared/coding-plugins';
import { CORE_CODING_SKILL_IDS } from '../../shared/coding-skills';
import type {
CapabilityBillingReceiptV1,
CapabilityResultV1,
@@ -427,22 +426,20 @@ export class CodingCapabilityRegistryImpl implements CodingCapabilityRegistryPor
skillRoots: [...skillRoots],
};
}
const assigned = [...new Set(input.assignedSkillIds)];
const coreIds = new Set<string>(CORE_CODING_SKILL_IDS);
const pluginSkillOwners = new Map<string, CodingPluginDefinition>();
for (const definition of this.definitions) {
for (const skill of definition.skills) pluginSkillOwners.set(skill.id, definition);
}
for (const id of assigned) {
if (!coreIds.has(id) && !pluginSkillOwners.has(id)) throw new Error(`Unknown bundled coding skill: ${id}`);
}
const effectiveCoreSkills = assigned.filter((id) => coreIds.has(id));
// Preserve legacy assignment IDs in project.json, but only providers in the
// current plugin registry may contribute resources to a new worker.
const assigned = [...new Set(input.assignedSkillIds)]
.filter((id) => pluginSkillOwners.has(id));
if (input.role === 'child') {
return {
catalogRevision: this.options.policyClient.getState().revision,
pluginIds: [],
effectiveSkillIds: effectiveCoreSkills,
skillEntries: effectiveCoreSkills.map((id) => ({ id, entryPath: `${id}/SKILL.md` })),
effectiveSkillIds: [],
skillEntries: [],
tools: [],
};
}
@@ -455,8 +452,8 @@ export class CodingCapabilityRegistryImpl implements CodingCapabilityRegistryPor
return {
catalogRevision: this.options.policyClient.getState().revision,
pluginIds: [],
effectiveSkillIds: effectiveCoreSkills,
skillEntries: effectiveCoreSkills.map((id) => ({ id, entryPath: `${id}/SKILL.md` })),
effectiveSkillIds: [],
skillEntries: [],
tools: [],
};
}
@@ -464,8 +461,8 @@ export class CodingCapabilityRegistryImpl implements CodingCapabilityRegistryPor
const enabled = await this.enabledPluginIds(input.projectPath);
const state = this.options.policyClient.getState();
const pluginIds: string[] = [];
const effectiveSkillIds = [...effectiveCoreSkills];
const skillEntries = effectiveCoreSkills.map((id) => ({ id, entryPath: `${id}/SKILL.md` }));
const effectiveSkillIds: string[] = [];
const skillEntries: Array<{ id: string; entryPath: string; packageRoot?: string }> = [];
const tools: CodingPluginToolDefinition[] = [];
for (const definition of this.definitions) {
if (!definition.requiresBackend || !enabled.includes(definition.id)