Skip to content

Commit 8582699

Browse files
committed
Refactor oneLevel scan logic to improve directory handling and wildcard support
1 parent 179d02c commit 8582699

1 file changed

Lines changed: 38 additions & 31 deletions

File tree

src/extension.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -431,46 +431,53 @@ class CopilotTokenTracker implements vscode.Disposable {
431431
});
432432
}
433433
} else if (scanMode === 'oneLevel') {
434-
// Find the first '*' segment to determine base directory
435-
// Treat oneLevel as: enumerate a single directory and glob-match within it.
434+
// Split at the first '*' wildcard to find base directory and remaining path
435+
// e.g., ".github/skills/*/SKILL.md" -> base: ".github/skills/", remaining: "/SKILL.md"
436436
const normalizedPattern = relativePattern.replace(/\\/g, '/');
437-
const segments = normalizedPattern.split('/').filter(s => s.length > 0);
438-
if (segments.length === 0) { continue; }
437+
const starIndex = normalizedPattern.indexOf('*');
438+
if (starIndex === -1) { continue; } // No wildcard, skip
439439

440-
// The last segment is the filename glob (e.g., "*.md"); preceding segments form the base directory.
441-
const filePattern = segments[segments.length - 1];
442-
const baseDirSegments = segments.slice(0, segments.length - 1);
443-
const baseDir = path.join(workspaceFolderPath, ...baseDirSegments);
440+
// Split the pattern at the '*'
441+
const beforeStar = normalizedPattern.substring(0, starIndex);
442+
const afterStar = normalizedPattern.substring(starIndex + 1);
443+
444+
// The base directory is everything before the '*' (trim trailing slash)
445+
const baseDirPath = beforeStar.replace(/\/$/, '');
446+
const baseDir = baseDirPath ? path.join(workspaceFolderPath, baseDirPath) : workspaceFolderPath;
444447

445448
if (!fs.existsSync(baseDir)) { continue; }
446449
const baseStat = fs.statSync(baseDir);
447450
if (!baseStat.isDirectory()) { continue; }
448451

449-
// Convert simple glob pattern to a RegExp for matching file names.
450-
const escaped = filePattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
451-
const regexSource = '^' + escaped.replace(/\*/g, '.*').replace(/\?/g, '.') + '$';
452-
const globRegex = new RegExp(regexSource);
453-
452+
// Enumerate directories in the base directory
454453
const entries = fs.readdirSync(baseDir, { withFileTypes: true });
455454
for (const entry of entries) {
456-
// Only consider files for oneLevel patterns.
457-
if (!entry.isFile()) { continue; }
458-
// Directory exclusions are irrelevant for files but keep the check harmlessly.
459-
if (entry.isDirectory() && excludeDirs.includes(entry.name)) { continue; }
460-
if (!globRegex.test(entry.name)) { continue; }
461-
462-
const absCandidate = path.join(baseDir, entry.name);
463-
const stat = fs.statSync(absCandidate);
464-
results.push({
465-
path: absCandidate,
466-
relativePath: path.relative(workspaceFolderPath, absCandidate).replace(/\\/g, '/'),
467-
type: pattern.type || 'unknown',
468-
icon: pattern.icon || '',
469-
label: pattern.label || path.basename(absCandidate),
470-
name: path.basename(absCandidate),
471-
lastModified: stat.mtime.toISOString(),
472-
isStale: (Date.now() - stat.mtime.getTime()) > stalenessDays * 24 * 60 * 60 * 1000
473-
});
455+
// Only consider directories at this level (unless afterStar is just a filename)
456+
if (excludeDirs.includes(entry.name)) { continue; }
457+
458+
// Construct the full path with this entry replacing the '*'
459+
const fullPattern = afterStar.startsWith('/') ? afterStar.substring(1) : afterStar;
460+
const candidatePath = path.join(baseDir, entry.name, fullPattern);
461+
462+
// Check if this path exists
463+
if (fs.existsSync(candidatePath)) {
464+
const stat = fs.statSync(candidatePath);
465+
if (stat.isFile()) {
466+
// For skills, use the directory name (parent of SKILL.md) as the display name
467+
const displayName = pattern.type === 'skill' ? entry.name : path.basename(candidatePath);
468+
469+
results.push({
470+
path: candidatePath,
471+
relativePath: path.relative(workspaceFolderPath, candidatePath).replace(/\\/g, '/'),
472+
type: pattern.type || 'unknown',
473+
icon: pattern.icon || '',
474+
label: pattern.label || displayName,
475+
name: displayName,
476+
lastModified: stat.mtime.toISOString(),
477+
isStale: (Date.now() - stat.mtime.getTime()) > stalenessDays * 24 * 60 * 60 * 1000
478+
});
479+
}
480+
}
474481
}
475482
} else if (scanMode === 'recursive') {
476483
const maxDepth = typeof pattern.maxDepth === 'number' ? pattern.maxDepth : 6;

0 commit comments

Comments
 (0)