feat: make project scaffold project-wide

This commit is contained in:
2026-09-05 12:34:36 +08:00
parent d642d7607c
commit 6710527e8f
9 changed files with 252 additions and 12 deletions

View File

@@ -3,6 +3,7 @@ import type {
CodingPluginDefinition,
CodingPluginToolDefinition,
} from '../../shared/coding-plugins';
import { isProjectWideCodingPluginId } from '../../shared/coding-plugins';
import {
CORE_CODING_SKILL_IDS,
type CodingSkillId,
@@ -240,6 +241,15 @@ function marketplaceSkillConflicts(records: readonly DefinitionRecord[]): Readon
return blocked;
}
function selectedSkillsForDefinition(
definition: CodingPluginDefinition,
assignedSkillIds: readonly string[],
): CodingPluginDefinition['skills'] {
return isProjectWideCodingPluginId(definition.id)
? definition.skills
: definition.skills.filter(({ id }) => assignedSkillIds.includes(id));
}
/**
* Resolve a worker snapshot from separated Marketplace, Package Store,
* project, assignment, and policy state. This module deliberately performs
@@ -303,7 +313,7 @@ export class EffectivePluginResolver {
const enabled = new Set(await this.enabledPluginIds(input.projectPath));
const requiresLibrary = userDefinitions.some(({ definition, installed }) => (
installed && enabled.has(definition.id)
&& definition.skills.some(({ id }) => assigned.includes(id))
&& selectedSkillsForDefinition(definition, assigned).length > 0
));
const library = input.library !== undefined
? input.library
@@ -314,7 +324,8 @@ export class EffectivePluginResolver {
const serverDefinitions = definitions.filter(({ definition }) => definition.requiresBackend);
const needsPolicyRefresh = policyState.status !== 'current'
&& serverDefinitions.some(({ definition, installed }) => (
installed && enabled.has(definition.id) && definition.skills.some(({ id }) => assigned.includes(id))
installed && enabled.has(definition.id)
&& selectedSkillsForDefinition(definition, assigned).length > 0
));
if (needsPolicyRefresh && this.options.policyClient) {
await this.options.policyClient.refresh();
@@ -330,7 +341,7 @@ export class EffectivePluginResolver {
));
continue;
}
const selectedSkills = definition.skills.filter(({ id }) => assigned.includes(id));
const selectedSkills = selectedSkillsForDefinition(definition, assigned);
if (selectedSkills.length === 0) {
unavailableReasons.push(unavailable(definition.id, 'skill_unassigned', 'Plugin Skill is not assigned'));
continue;