mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 00:03:00 +00:00
fix(coding-agent): align auto-discovery with loader rules
This commit is contained in:
parent
b270e7b585
commit
585ce73be1
5 changed files with 139 additions and 63 deletions
|
|
@ -169,7 +169,7 @@ function collectFiles(dir: string, filePattern: RegExp, skipNodeModules = true):
|
|||
return files;
|
||||
}
|
||||
|
||||
function collectSkillEntries(dir: string): string[] {
|
||||
function collectSkillEntries(dir: string, includeRootFiles = true): string[] {
|
||||
const entries: string[] = [];
|
||||
if (!existsSync(dir)) return entries;
|
||||
|
||||
|
|
@ -194,14 +194,13 @@ function collectSkillEntries(dir: string): string[] {
|
|||
}
|
||||
|
||||
if (isDir) {
|
||||
const skillMd = join(fullPath, "SKILL.md");
|
||||
if (existsSync(skillMd)) {
|
||||
entries.push(...collectSkillEntries(fullPath, false));
|
||||
} else if (isFile) {
|
||||
const isRootMd = includeRootFiles && entry.name.endsWith(".md");
|
||||
const isSkillMd = !includeRootFiles && entry.name === "SKILL.md";
|
||||
if (isRootMd || isSkillMd) {
|
||||
entries.push(fullPath);
|
||||
} else {
|
||||
entries.push(...collectSkillEntries(fullPath));
|
||||
}
|
||||
} else if (isFile && entry.name.endsWith(".md")) {
|
||||
entries.push(fullPath);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
|
@ -211,48 +210,8 @@ function collectSkillEntries(dir: string): string[] {
|
|||
return entries;
|
||||
}
|
||||
|
||||
function collectAutoSkillEntries(dir: string, isRoot = true): string[] {
|
||||
const entries: string[] = [];
|
||||
if (!existsSync(dir)) return entries;
|
||||
|
||||
try {
|
||||
const dirEntries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of dirEntries) {
|
||||
if (entry.name.startsWith(".")) continue;
|
||||
if (entry.name === "node_modules") continue;
|
||||
|
||||
const fullPath = join(dir, entry.name);
|
||||
let isDir = entry.isDirectory();
|
||||
let isFile = entry.isFile();
|
||||
|
||||
if (entry.isSymbolicLink()) {
|
||||
try {
|
||||
const stats = statSync(fullPath);
|
||||
isDir = stats.isDirectory();
|
||||
isFile = stats.isFile();
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDir) {
|
||||
const skillMd = join(fullPath, "SKILL.md");
|
||||
if (existsSync(skillMd)) {
|
||||
entries.push(fullPath);
|
||||
} else {
|
||||
entries.push(...collectAutoSkillEntries(fullPath, false));
|
||||
}
|
||||
} else if (isFile && entry.name.endsWith(".md")) {
|
||||
if (isRoot || entry.name === "SKILL.md") {
|
||||
entries.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors
|
||||
}
|
||||
|
||||
return entries;
|
||||
function collectAutoSkillEntries(dir: string, includeRootFiles = true): string[] {
|
||||
return collectSkillEntries(dir, includeRootFiles);
|
||||
}
|
||||
|
||||
function collectAutoPromptEntries(dir: string): string[] {
|
||||
|
|
@ -400,9 +359,18 @@ function collectAutoExtensionEntries(dir: string): string[] {
|
|||
function matchesAnyPattern(filePath: string, patterns: string[], baseDir: string): boolean {
|
||||
const rel = relative(baseDir, filePath);
|
||||
const name = basename(filePath);
|
||||
return patterns.some(
|
||||
(pattern) => minimatch(rel, pattern) || minimatch(name, pattern) || minimatch(filePath, pattern),
|
||||
);
|
||||
const isSkillFile = name === "SKILL.md";
|
||||
const parentDir = isSkillFile ? dirname(filePath) : undefined;
|
||||
const parentRel = isSkillFile ? relative(baseDir, parentDir!) : undefined;
|
||||
const parentName = isSkillFile ? basename(parentDir!) : undefined;
|
||||
|
||||
return patterns.some((pattern) => {
|
||||
if (minimatch(rel, pattern) || minimatch(name, pattern) || minimatch(filePath, pattern)) {
|
||||
return true;
|
||||
}
|
||||
if (!isSkillFile) return false;
|
||||
return minimatch(parentRel!, pattern) || minimatch(parentName!, pattern) || minimatch(parentDir!, pattern);
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeExactPattern(pattern: string): string {
|
||||
|
|
@ -415,9 +383,18 @@ function normalizeExactPattern(pattern: string): string {
|
|||
function matchesAnyExactPattern(filePath: string, patterns: string[], baseDir: string): boolean {
|
||||
if (patterns.length === 0) return false;
|
||||
const rel = relative(baseDir, filePath);
|
||||
const name = basename(filePath);
|
||||
const isSkillFile = name === "SKILL.md";
|
||||
const parentDir = isSkillFile ? dirname(filePath) : undefined;
|
||||
const parentRel = isSkillFile ? relative(baseDir, parentDir!) : undefined;
|
||||
|
||||
return patterns.some((pattern) => {
|
||||
const normalized = normalizeExactPattern(pattern);
|
||||
return normalized === rel || normalized === filePath;
|
||||
if (normalized === rel || normalized === filePath) {
|
||||
return true;
|
||||
}
|
||||
if (!isSkillFile) return false;
|
||||
return normalized === parentRel || normalized === parentDir;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,24 +268,52 @@ export class DefaultResourceLoader implements ResourceLoader {
|
|||
});
|
||||
|
||||
// Helper to extract enabled paths and store metadata
|
||||
const getEnabledPaths = (
|
||||
const getEnabledResources = (
|
||||
resources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,
|
||||
): string[] => {
|
||||
): Array<{ path: string; enabled: boolean; metadata: PathMetadata }> => {
|
||||
for (const r of resources) {
|
||||
if (!this.pathMetadata.has(r.path)) {
|
||||
this.pathMetadata.set(r.path, r.metadata);
|
||||
}
|
||||
}
|
||||
return resources.filter((r) => r.enabled).map((r) => r.path);
|
||||
return resources.filter((r) => r.enabled);
|
||||
};
|
||||
|
||||
const getEnabledPaths = (
|
||||
resources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,
|
||||
): string[] => getEnabledResources(resources).map((r) => r.path);
|
||||
|
||||
// Store metadata and get enabled paths
|
||||
this.pathMetadata = new Map();
|
||||
const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
|
||||
const enabledSkills = getEnabledPaths(resolvedPaths.skills);
|
||||
const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
|
||||
const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
|
||||
const enabledThemes = getEnabledPaths(resolvedPaths.themes);
|
||||
|
||||
const mapSkillPath = (resource: { path: string; metadata: PathMetadata }): string => {
|
||||
if (resource.metadata.source !== "auto" && resource.metadata.origin !== "package") {
|
||||
return resource.path;
|
||||
}
|
||||
try {
|
||||
const stats = statSync(resource.path);
|
||||
if (!stats.isDirectory()) {
|
||||
return resource.path;
|
||||
}
|
||||
} catch {
|
||||
return resource.path;
|
||||
}
|
||||
const skillFile = join(resource.path, "SKILL.md");
|
||||
if (existsSync(skillFile)) {
|
||||
if (!this.pathMetadata.has(skillFile)) {
|
||||
this.pathMetadata.set(skillFile, resource.metadata);
|
||||
}
|
||||
return skillFile;
|
||||
}
|
||||
return resource.path;
|
||||
};
|
||||
|
||||
const enabledSkills = enabledSkillResources.map(mapSkillPath);
|
||||
|
||||
// Add CLI paths metadata
|
||||
for (const r of cliExtensionPaths.extensions) {
|
||||
if (!this.pathMetadata.has(r.path)) {
|
||||
|
|
|
|||
|
|
@ -98,12 +98,14 @@ function buildGroups(resolved: ResolvedPaths): ResourceGroup[] {
|
|||
group.subgroups.push(subgroup);
|
||||
}
|
||||
|
||||
const displayName =
|
||||
resourceType === "skills" && basename(path) === "SKILL.md" ? basename(dirname(path)) : basename(path);
|
||||
subgroup.items.push({
|
||||
path,
|
||||
enabled,
|
||||
metadata,
|
||||
resourceType,
|
||||
displayName: basename(path),
|
||||
displayName,
|
||||
groupKey,
|
||||
subgroupKey,
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue