fix: harden install planning and sync tracked catalogs

This commit is contained in:
Affaan Mustafa
2026-03-31 22:57:48 -07:00
parent 03c4a90ffa
commit e1bc08fa6e
19 changed files with 970 additions and 118 deletions

View File

@@ -1,7 +1,7 @@
const fs = require('fs');
const os = require('os');
const path = require('path');
const { planInstallTargetScaffold } = require('./install-targets/registry');
const { getInstallTargetAdapter, planInstallTargetScaffold } = require('./install-targets/registry');
const DEFAULT_REPO_ROOT = path.join(__dirname, '../..');
const SUPPORTED_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity', 'codex', 'gemini', 'opencode', 'codebuddy'];
@@ -76,6 +76,48 @@ function dedupeStrings(values) {
return [...new Set((Array.isArray(values) ? values : []).map(value => String(value).trim()).filter(Boolean))];
}
function readOptionalStringOption(options, key) {
if (
!Object.prototype.hasOwnProperty.call(options, key)
|| options[key] === null
|| options[key] === undefined
) {
return null;
}
if (typeof options[key] !== 'string' || options[key].trim() === '') {
throw new Error(`${key} must be a non-empty string when provided`);
}
return options[key];
}
function readModuleTargetsOrThrow(module) {
const moduleId = module && module.id ? module.id : '<unknown>';
const targets = module && module.targets;
if (!Array.isArray(targets)) {
throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);
}
const normalizedTargets = targets.map(target => (
typeof target === 'string' ? target.trim() : ''
));
if (normalizedTargets.some(target => target.length === 0)) {
throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);
}
const unsupportedTargets = normalizedTargets.filter(target => !SUPPORTED_INSTALL_TARGETS.includes(target));
if (unsupportedTargets.length > 0) {
throw new Error(
`Install module ${moduleId} has unsupported targets: ${unsupportedTargets.join(', ')}`
);
}
return normalizedTargets;
}
function assertKnownModuleIds(moduleIds, manifests) {
const unknownModuleIds = dedupeStrings(moduleIds)
.filter(moduleId => !manifests.modulesById.has(moduleId));
@@ -125,6 +167,11 @@ function loadInstallManifests(options = {}) {
? profilesData.profiles
: {};
const components = Array.isArray(componentsData.components) ? componentsData.components : [];
for (const module of modules) {
readModuleTargetsOrThrow(module);
}
const modulesById = new Map(modules.map(module => [module.id, module]));
const componentsById = new Map(components.map(component => [component.id, component]));
@@ -361,6 +408,16 @@ function resolveInstallPlan(options = {}) {
`Unknown install target: ${target}. Expected one of ${SUPPORTED_INSTALL_TARGETS.join(', ')}`
);
}
const validatedProjectRoot = readOptionalStringOption(options, 'projectRoot');
const validatedHomeDir = readOptionalStringOption(options, 'homeDir');
const targetPlanningInput = target
? {
repoRoot: manifests.repoRoot,
projectRoot: validatedProjectRoot || manifests.repoRoot,
homeDir: validatedHomeDir || os.homedir(),
}
: null;
const targetAdapter = target ? getInstallTargetAdapter(target) : null;
const effectiveRequestedIds = dedupeStrings(
requestedModuleIds.filter(moduleId => !excludedModuleOwners.has(moduleId))
@@ -396,7 +453,13 @@ function resolveInstallPlan(options = {}) {
return;
}
if (target && !module.targets.includes(target)) {
const supportsTarget = !target
|| (
readModuleTargetsOrThrow(module).includes(target)
&& (!targetAdapter || targetAdapter.supportsModule(module, targetPlanningInput))
);
if (!supportsTarget) {
if (dependencyOf) {
skippedTargetIds.add(rootRequesterId || dependencyOf);
return false;
@@ -444,9 +507,9 @@ function resolveInstallPlan(options = {}) {
const scaffoldPlan = target
? planInstallTargetScaffold({
target,
repoRoot: manifests.repoRoot,
projectRoot: options.projectRoot || manifests.repoRoot,
homeDir: options.homeDir || os.homedir(),
repoRoot: targetPlanningInput.repoRoot,
projectRoot: targetPlanningInput.projectRoot,
homeDir: targetPlanningInput.homeDir,
modules: selectedModules,
})
: null;