* Fallback path used when an explicit single-skill source points at a flat skill * with root-level files. Fetches and writes that skill into `fetchedSkills`. * Returns whether the fallback fired and the resulting remote skill names.
(params: {
entries: GitHubFileEntry[];
parsed: ParsedSource;
ref: string;
resolvedSha: string;
skillFilter: string[];
isWildcard: boolean;
curatedDir: string;
locked: LockedSource | undefined;
sourceKey: string;
localSkillNames: Set<string>;
alreadyFetchedSkillNames: Set<string>;
client: GitHubClient;
semaphore: Semaphore;
fetchedSkills: Record<string, LockedSkill>;
logger: Logger;
})
| 517 | * Returns whether the fallback fired and the resulting remote skill names. |
| 518 | */ |
| 519 | async function fetchRootLevelFallbackSkill(params: { |
| 520 | entries: GitHubFileEntry[]; |
| 521 | parsed: ParsedSource; |
| 522 | ref: string; |
| 523 | resolvedSha: string; |
| 524 | skillFilter: string[]; |
| 525 | isWildcard: boolean; |
| 526 | curatedDir: string; |
| 527 | locked: LockedSource | undefined; |
| 528 | sourceKey: string; |
| 529 | localSkillNames: Set<string>; |
| 530 | alreadyFetchedSkillNames: Set<string>; |
| 531 | client: GitHubClient; |
| 532 | semaphore: Semaphore; |
| 533 | fetchedSkills: Record<string, LockedSkill>; |
| 534 | logger: Logger; |
| 535 | }): Promise<{ handled: boolean; remoteSkillNames: string[] }> { |
| 536 | const { |
| 537 | entries, |
| 538 | parsed, |
| 539 | ref, |
| 540 | resolvedSha, |
| 541 | skillFilter, |
| 542 | isWildcard, |
| 543 | curatedDir, |
| 544 | locked, |
| 545 | sourceKey, |
| 546 | localSkillNames, |
| 547 | alreadyFetchedSkillNames, |
| 548 | client, |
| 549 | semaphore, |
| 550 | fetchedSkills, |
| 551 | logger, |
| 552 | } = params; |
| 553 | |
| 554 | const rootFiles = entries.filter((entry) => entry.type === "file"); |
| 555 | const rootSkillFiles: RemoteSkillFile[] = []; |
| 556 | |
| 557 | for (const file of rootFiles) { |
| 558 | if (file.size > MAX_FILE_SIZE) { |
| 559 | logger.warn( |
| 560 | `Skipping file "${file.path}" (${(file.size / 1024 / 1024).toFixed(2)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit).`, |
| 561 | ); |
| 562 | continue; |
| 563 | } |
| 564 | const content = await withSemaphore(semaphore, () => |
| 565 | client.getFileContent(parsed.owner, parsed.repo, file.path, ref), |
| 566 | ); |
| 567 | rootSkillFiles.push({ relativePath: file.name, content }); |
| 568 | } |
| 569 | |
| 570 | const groupedRootFiles = groupRemoteFilesBySkillRoot({ |
| 571 | remoteFiles: rootSkillFiles, |
| 572 | skillFilter, |
| 573 | isWildcard, |
| 574 | }); |
| 575 | const [fallbackSkillName] = groupedRootFiles.keys(); |
| 576 | if (fallbackSkillName === undefined) { |
no test coverage detected
searching dependent graphs…