fix(coding): remediate ML-07 plugin authority
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { readFile, readdir } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { DATA_SERVICE_PLUGIN_DEFINITION } from '../../shared/coding-plugins';
|
||||
import {
|
||||
BUNDLED_CODING_SKILL_IDS,
|
||||
type BundledCodingSkillId,
|
||||
type CodingSkillId,
|
||||
} from '../../shared/coding-skills';
|
||||
import type {
|
||||
ProductCodingCommand,
|
||||
@@ -29,7 +28,9 @@ const COMMAND_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
|
||||
|
||||
export interface ProductCodingPluginSkillSource {
|
||||
id: string;
|
||||
pluginId?: string;
|
||||
directory: string;
|
||||
available?: boolean;
|
||||
/** Package-relative Skill entry; defaults to `SKILL.md`. */
|
||||
entryPath?: string;
|
||||
}
|
||||
@@ -47,20 +48,6 @@ function frontmatterScalar(content: string, key: string): string | undefined {
|
||||
return value || undefined;
|
||||
}
|
||||
|
||||
function defaultPluginSkillSources(bundledSkillsDir: string): ProductCodingPluginSkillSource[] {
|
||||
const skillId = DATA_SERVICE_PLUGIN_DEFINITION.skills[0]?.id ?? 'data-service';
|
||||
return [{
|
||||
id: skillId,
|
||||
directory: path.join(
|
||||
path.dirname(path.resolve(bundledSkillsDir)),
|
||||
'coding-plugins',
|
||||
'data-service',
|
||||
'skills',
|
||||
'data-service',
|
||||
),
|
||||
}];
|
||||
}
|
||||
|
||||
function selectedSkillIds(
|
||||
value: readonly string[],
|
||||
allIds: readonly string[],
|
||||
@@ -75,11 +62,8 @@ function selectedSkillIds(
|
||||
return selected;
|
||||
}
|
||||
|
||||
function productSkillId(id: string): BundledCodingSkillId {
|
||||
// ProductCodingSkill predates package-owned Skill ids. The registry is
|
||||
// the trusted projection boundary, so the runtime value may contain a
|
||||
// package Skill while the shared contract is migrated by the caller.
|
||||
return id as BundledCodingSkillId;
|
||||
function productSkillId(id: string): CodingSkillId {
|
||||
return id;
|
||||
}
|
||||
|
||||
async function listSkillEntries(
|
||||
@@ -103,7 +87,7 @@ async function listSkillEntries(
|
||||
export async function listProductCodingSkills(
|
||||
bundledSkillsDir: string,
|
||||
selectedIds: readonly string[] = [],
|
||||
pluginSkillSources: readonly ProductCodingPluginSkillSource[] = defaultPluginSkillSources(bundledSkillsDir),
|
||||
pluginSkillSources: readonly ProductCodingPluginSkillSource[] = [],
|
||||
): Promise<ProductCodingSkill[]> {
|
||||
const pluginIds = pluginSkillSources.map(({ id }) => id);
|
||||
const allIds = [...BUNDLED_CODING_SKILL_IDS, ...pluginIds];
|
||||
@@ -118,7 +102,8 @@ export async function listProductCodingSkills(
|
||||
})),
|
||||
...pluginSkillSources,
|
||||
];
|
||||
return await Promise.all(sources.map(async ({ id, directory, entryPath }) => {
|
||||
const visibleSources = sources.filter(({ id, available }) => available !== false || selected.has(id));
|
||||
return await Promise.all(visibleSources.map(async ({ id, directory, entryPath, available = true }) => {
|
||||
const location = path.resolve(directory);
|
||||
const content = await readFile(path.join(location, entryPath ?? 'SKILL.md'), 'utf8');
|
||||
return {
|
||||
@@ -126,6 +111,8 @@ export async function listProductCodingSkills(
|
||||
name: frontmatterScalar(content, 'name') ?? id,
|
||||
description: frontmatterScalar(content, 'description') ?? '',
|
||||
selected: selected.has(id),
|
||||
available,
|
||||
effective: available && selected.has(id),
|
||||
location,
|
||||
content,
|
||||
entries: await listSkillEntries(location),
|
||||
@@ -153,7 +140,7 @@ export function buildProductCodingCommandCatalog(
|
||||
}
|
||||
for (const skill of skills) {
|
||||
const key = skill.id.toLocaleLowerCase();
|
||||
if (!skill.selected || used.has(key)) continue;
|
||||
if (!skill.effective || used.has(key)) continue;
|
||||
used.add(key);
|
||||
commands.push({
|
||||
name: skill.id,
|
||||
|
||||
Reference in New Issue
Block a user