(selector: string)
| 732 | } |
| 733 | |
| 734 | async function resolveProjectSelector(selector: string): Promise<ProjectResolution> { |
| 735 | const trimmedSelector = selector.trim(); |
| 736 | if (!trimmedSelector) { |
| 737 | return { |
| 738 | ok: false, |
| 739 | response: buildProjectSelectionError( |
| 740 | 'unknown_project', |
| 741 | 'project must be a non-empty absolute path, file:// URI, or relative subproject path.' |
| 742 | ) |
| 743 | }; |
| 744 | } |
| 745 | |
| 746 | if (trimmedSelector.startsWith('file://') || path.isAbsolute(trimmedSelector)) { |
| 747 | const resolvedPath = parseProjectDirectory(trimmedSelector); |
| 748 | if (!resolvedPath) { |
| 749 | return { |
| 750 | ok: false, |
| 751 | response: buildProjectSelectionError( |
| 752 | 'unknown_project', |
| 753 | 'project must be a non-empty absolute path, file:// URI, or relative subproject path.' |
| 754 | ) |
| 755 | }; |
| 756 | } |
| 757 | return resolveProjectFromAbsolutePath(resolvedPath); |
| 758 | } |
| 759 | |
| 760 | const normalizedSelector = trimmedSelector.replace(/\\/g, '/').replace(/^\.\/+/, ''); |
| 761 | const descriptorMatches = listProjectDescriptors().filter( |
| 762 | (descriptor) => |
| 763 | descriptor.label === normalizedSelector || |
| 764 | descriptor.relativePath === normalizedSelector || |
| 765 | path.basename(descriptor.rootPath) === normalizedSelector |
| 766 | ); |
| 767 | |
| 768 | if (descriptorMatches.length === 1) { |
| 769 | const matchedRootPath = descriptorMatches[0].rootPath; |
| 770 | if (descriptorMatches[0].source === 'subdirectory') { |
| 771 | registerDiscoveredProjectPath(matchedRootPath, 'subdirectory'); |
| 772 | } else { |
| 773 | rememberProjectPath(matchedRootPath, classifyProjectSource(matchedRootPath), { |
| 774 | touch: false |
| 775 | }); |
| 776 | } |
| 777 | const project = getOrCreateProject(matchedRootPath); |
| 778 | return { ok: true, project }; |
| 779 | } |
| 780 | |
| 781 | if (descriptorMatches.length > 1) { |
| 782 | return { |
| 783 | ok: false, |
| 784 | response: buildProjectSelectionError( |
| 785 | 'selection_required', |
| 786 | `Project selector "${normalizedSelector}" matches multiple known projects. Retry with an absolute path.`, |
| 787 | { |
| 788 | reason: 'project_selector_ambiguous', |
| 789 | nextAction: 'retry_with_project' |
| 790 | } |
| 791 | ) |
no test coverage detected