fix: declare optional cross-target install dependencies

Carry forward the final scoped delta of PR #3119 at 60e82f95. Keep required dependency closure and select only modules reachable from successful requests; refresh the unchanged 293-skill registry binding.
This commit is contained in:
Dante
2026-10-09 15:43:31 -04:00
committed by haelyra
parent ef648e0189
commit c29a724bcd
6 changed files with 129 additions and 16 deletions
+7
View File
@@ -123,6 +123,13 @@ function validateInstallManifests() {
}
}
for (const dependency of module.optionalDependencies || []) {
if (!module.dependencies.includes(dependency)) {
console.error(`ERROR: Module ${module.id} optional dependency ${dependency} is not a declared dependency`);
hasErrors = true;
}
}
for (const relativePath of module.paths) {
const normalizedPath = normalizeRelativePath(relativePath);
const absolutePath = path.join(REPO_ROOT, normalizedPath);
+28 -9
View File
@@ -325,6 +325,12 @@ function loadInstallManifests(options = {}) {
for (const module of modules) {
readModuleTargetsOrThrow(module);
if (module.optionalDependencies !== undefined && (
!Array.isArray(module.optionalDependencies)
|| module.optionalDependencies.some(id => !module.dependencies.includes(id))
)) {
throw new Error(`Install module ${module.id} optionalDependencies must be an array of declared dependency ids`);
}
}
const modulesById = new Map(modules.map(module => [module.id, module]));
@@ -633,7 +639,7 @@ function resolveInstallPlan(options = {}) {
const visitingIds = new Set();
const resolvedIds = new Set();
function resolveModule(moduleId, dependencyOf, rootRequesterId) {
function resolveModule(moduleId, dependencyOf, optional = false) {
const module = manifests.modulesById.get(moduleId);
if (!module) {
throw new Error(`Unknown install module: ${moduleId}`);
@@ -657,8 +663,9 @@ function resolveInstallPlan(options = {}) {
if (!supportsTarget) {
if (dependencyOf) {
skippedTargetIds.add(rootRequesterId || dependencyOf);
return false;
// Only explicitly optional edges may be omitted for this target.
skippedTargetIds.add(moduleId);
return optional;
}
skippedTargetIds.add(moduleId);
return false;
@@ -677,24 +684,36 @@ function resolveInstallPlan(options = {}) {
const dependencyResolved = resolveModule(
dependencyId,
moduleId,
rootRequesterId || moduleId
(module.optionalDependencies || []).includes(dependencyId)
);
if (!dependencyResolved) {
visitingIds.delete(moduleId);
if (!dependencyOf) {
skippedTargetIds.add(moduleId);
}
skippedTargetIds.add(moduleId);
return false;
}
}
visitingIds.delete(moduleId);
resolvedIds.add(moduleId);
selectedIds.add(moduleId);
return true;
}
// Resolution may visit supported dependencies before a later required edge fails.
// Select only the closure of successful requests, so failed requests leave no
// orphan modules while shared dependencies remain available to successful ones.
function selectResolvedModule(moduleId) {
if (!resolvedIds.has(moduleId) || selectedIds.has(moduleId)) {
return;
}
selectedIds.add(moduleId);
for (const dependencyId of manifests.modulesById.get(moduleId).dependencies) {
selectResolvedModule(dependencyId);
}
}
for (const moduleId of effectiveRequestedIds) {
resolveModule(moduleId, null, moduleId);
if (resolveModule(moduleId, null)) {
selectResolvedModule(moduleId);
}
}
const selectedModules = manifests.modules.filter(module => selectedIds.has(module.id));