feat: wire manifest resolution into install execution#509
Conversation
📝 WalkthroughWalkthroughThis PR adds comprehensive legacy compatibility support to the install system, introducing language-to-module mapping for legacy install arguments, explicit module selection via --modules CLI flag, and manifest-driven profile resolution. It establishes a new 'legacy-compat' mode with supporting functions and updates request/runtime handling accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI Arguments
participant Request as Request Parser
participant Manifest as Manifest Loader
participant Executor as Install Executor
participant Runtime as Runtime Resolver
CLI->>Request: Parse legacy languages & modules
Request->>Request: Validate moduleIds via Manifests
Request->>Request: Normalize to legacyLanguages
Request-->>Runtime: Return {mode: 'legacy-compat', legacyLanguages}
Runtime->>Executor: createLegacyCompatInstallPlan()
Executor->>Manifest: resolveLegacyCompatibilitySelection()
Manifest->>Manifest: Map languages to canonical form
Manifest->>Manifest: Build base + extra module IDs
Manifest-->>Executor: Return {languages, moduleIds}
Executor->>Manifest: resolveInstallPlan()
Manifest-->>Executor: Return manifest-driven install plan
Executor-->>Runtime: Return install plan with legacy metadata
Runtime-->>CLI: Execute file operations per plan
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR wires Key changes:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as install-apply.js
participant Req as install/request.js
participant RT as install/runtime.js
participant Exec as install-executor.js
participant Mfst as install-manifests.js
CLI->>Req: parseInstallArgs(argv)
CLI->>Req: normalizeInstallRequest(options)
Req->>Mfst: validateInstallModuleIds(moduleIds)
Mfst-->>Req: validated & deduped IDs
Req-->>CLI: request { mode: 'legacy-compat' | 'manifest' }
CLI->>RT: createInstallPlanFromRequest(request)
alt mode === 'legacy-compat'
RT->>Exec: createLegacyCompatInstallPlan(options)
Exec->>Mfst: resolveLegacyCompatibilitySelection({ target, legacyLanguages })
Mfst-->>Exec: { moduleIds, legacyLanguages, canonicalLegacyLanguages }
Exec->>Exec: createManifestInstallPlan(selection + legacyMode=true)
else mode === 'manifest'
RT->>Exec: createManifestInstallPlan(options)
else mode === 'legacy'
RT->>Exec: createLegacyInstallPlan(options)
end
Exec->>Mfst: resolveInstallPlan({ profileId, moduleIds, target })
Note over Mfst: resolveModule() skips incompatible<br/>dependency trees (returns false)<br/>instead of throwing
Mfst-->>Exec: { selectedModuleIds, skippedModuleIds, operations }
Exec-->>RT: plan { mode, legacyLanguages, statePreview, operations }
RT-->>CLI: plan
alt --dry-run
CLI->>CLI: printHumanPlan(plan) / JSON.stringify
else apply
CLI->>Exec: applyInstallPlan(plan)
Exec-->>CLI: result
end
Last reviewed commit: b320fb3 |
| const baseModuleIds = LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET[target || 'claude'] | ||
| || LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET.claude; |
There was a problem hiding this comment.
Silent fallback to claude base modules for unsupported targets
resolveLegacyCompatibilitySelection validates target against the full SUPPORTED_INSTALL_TARGETS list (which includes codex and opencode), but LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET only defines entries for claude, cursor, and antigravity. An unknown key lookup returns undefined, which then silently falls back to the claude config via the || chain:
const baseModuleIds = LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET[target || 'claude']
|| LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET.claude;If this function is called with target: 'codex' or target: 'opencode' (both valid according to the guard on line 229), it will silently install claude-flavoured base modules instead of throwing a clear error. While the current call site in createLegacyCompatInstallPlan is protected by validateLegacyTarget, the public export of resolveLegacyCompatibilitySelection means future callers, tests, or direct usage could hit this silently wrong path.
The validation on line 229 should mirror the entries in LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET rather than the broader SUPPORTED_INSTALL_TARGETS:
| const baseModuleIds = LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET[target || 'claude'] | |
| || LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET.claude; | |
| if (target && !Object.hasOwn(LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET, target || 'claude')) { | |
| throw new Error( | |
| `Unknown install target: ${target}. Expected one of ${Object.keys(LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET).join(', ')}` | |
| ); | |
| } |
| for (const dependencyId of module.dependencies) { | ||
| resolveModule(dependencyId, moduleId); | ||
| const dependencyResolved = resolveModule( | ||
| dependencyId, | ||
| moduleId, | ||
| rootRequesterId || moduleId | ||
| ); | ||
| if (!dependencyResolved) { | ||
| visitingIds.delete(moduleId); | ||
| if (!dependencyOf) { | ||
| skippedTargetIds.add(moduleId); | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| visitingIds.delete(moduleId); | ||
| resolvedIds.add(moduleId); | ||
| selectedIds.add(moduleId); | ||
| return true; |
There was a problem hiding this comment.
Orphaned modules left in selectedIds when a later sibling dependency fails target check
When resolving module A's dependencies in order [D1, D2]:
D1is target-compatible →D1(and all its transitive deps) are added toselectedIdsandresolvedIdsD2is target-incompatible →Ais added toskippedTargetIds,falseis returnedAis not added toselectedIds— butD1is still there from step 1
D1 now appears in the final selectedModules even though the only top-level requester (A) was ultimately skipped. In shallow dependency trees this may be harmless (D1 might be requested elsewhere), but in deep or unique chains this results in modules being installed that have no remaining requester.
A minimal fix is to track which modules were added during the resolution of a particular root module and roll them back on failure:
visitingIds.add(moduleId);
const addedThisRound = [];
for (const dependencyId of module.dependencies) {
const dependencyResolved = resolveModule(dependencyId, moduleId, rootRequesterId || moduleId);
if (!dependencyResolved) {
// roll back any modules added while resolving this branch
for (const id of addedThisRound) { selectedIds.delete(id); resolvedIds.delete(id); }
visitingIds.delete(moduleId);
if (!dependencyOf) { skippedTargetIds.add(moduleId); }
return false;
}
addedThisRound.push(dependencyId);
}At minimum, this should be documented so future contributors are aware of the partial-selection behaviour.
| const moduleIds = validateInstallModuleIds( | ||
| dedupeStrings([...(config?.moduleIds || []), ...(options.moduleIds || [])]) | ||
| ); |
There was a problem hiding this comment.
Manifest always loaded even when moduleIds is empty
validateInstallModuleIds unconditionally calls loadInstallManifests, which reads and parses three JSON files from disk. When moduleIds is an empty array there are no IDs to validate, so the file I/O is wasted on every normalizeInstallRequest call that doesn't supply modules (e.g., all legacy-language installs).
A cheap guard avoids the unnecessary I/O:
| const moduleIds = validateInstallModuleIds( | |
| dedupeStrings([...(config?.moduleIds || []), ...(options.moduleIds || [])]) | |
| ); | |
| const rawModuleIds = dedupeStrings([...(config?.moduleIds || []), ...(options.moduleIds || [])]); | |
| const moduleIds = rawModuleIds.length > 0 | |
| ? validateInstallModuleIds(rawModuleIds) | |
| : rawModuleIds; |
| if (request.mode === 'legacy-compat') { | ||
| return createLegacyCompatInstallPlan({ | ||
| target: request.target, | ||
| legacyLanguages: request.legacyLanguages, | ||
| projectRoot: options.projectRoot, | ||
| homeDir: options.homeDir, | ||
| claudeRulesDir: options.claudeRulesDir, | ||
| sourceRoot: options.sourceRoot, | ||
| }); | ||
| } |
There was a problem hiding this comment.
claudeRulesDir forwarded but silently dropped in legacy-compat path
createLegacyCompatInstallPlan accepts claudeRulesDir in its options object (forwarded here from install-apply.js via CLAUDE_RULES_DIR), but neither createLegacyCompatInstallPlan nor the downstream createManifestInstallPlan consumes it. The old legacy mode honoured this env var to redirect the Claude rules destination; the new legacy-compat path silently ignores it.
This is a quiet breaking change for users who set CLAUDE_RULES_DIR. Consider either:
- Explicitly documenting that
CLAUDE_RULES_DIRis no longer respected inlegacy-compatmode, or - Surfacing a warning when
claudeRulesDiris non-null and the mode islegacy-compat.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b320fb3539
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| visitingIds.delete(moduleId); | ||
| if (!dependencyOf) { | ||
| skippedTargetIds.add(moduleId); | ||
| } | ||
| return false; |
There was a problem hiding this comment.
Roll back resolved deps when skipping a module
When resolveModule bails out on an incompatible dependency, it returns false but keeps dependencies that were already added to selectedIds earlier in the same traversal. For mixed-support trees this installs modules even though the requested root is skipped: for example, resolving framework-language on antigravity selects rules-core/agents-core/commands-core before failing on platform-configs, so the plan applies partial modules instead of skipping the incompatible tree. This changes install results for explicit module requests and can unexpectedly mutate targets with modules users did not successfully request.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
scripts/lib/install-manifests.js (1)
235-237: Minor: Redundant deduplication.Line 235 calls
dedupeStrings()onoptions.legacyLanguages, then line 237 calls it again onlegacyLanguages. SincededupeStringsalready returns deduplicated values, the second call is redundant.♻️ Simplify deduplication
- const legacyLanguages = dedupeStrings(options.legacyLanguages) - .map(language => language.toLowerCase()); - const normalizedLegacyLanguages = dedupeStrings(legacyLanguages); + const normalizedLegacyLanguages = dedupeStrings(options.legacyLanguages) + .map(language => language.toLowerCase());Note: This assumes case-insensitive deduplication is acceptable. If
['Go', 'go']should dedupe to one entry, you'd need to dedupe after lowercasing:const normalizedLegacyLanguages = [...new Set( dedupeStrings(options.legacyLanguages).map(l => l.toLowerCase()) )];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/lib/install-manifests.js` around lines 235 - 237, The code calls dedupeStrings twice (on options.legacyLanguages and then again on legacyLanguages) causing redundant work; update the logic around dedupeStrings, legacyLanguages, and normalizedLegacyLanguages so you only deduplicate once and then normalize case as needed: call dedupeStrings on options.legacyLanguages (or lowercase first then dedupe if you need case-insensitive results), assign that to legacyLanguages, then derive normalizedLegacyLanguages without re-calling dedupeStrings (e.g., map toLowerCase and use a Set or dedupe once), ensuring the variable names legacyLanguages and normalizedLegacyLanguages reflect the single deduplication step.tests/scripts/install-apply.test.js (1)
176-176: Avoid order-coupled assertions for selected modules.These
deepStrictEqual([...])checks are brittle if resolver ordering changes while module membership remains correct. Prefer order-insensitive comparison.♻️ Suggested refactor
- assert.deepStrictEqual(state.resolution.selectedModules, ['rules-core', 'agents-core', 'commands-core']); + assert.deepStrictEqual( + [...state.resolution.selectedModules].sort(), + ['rules-core', 'agents-core', 'commands-core'].sort() + );Also applies to: 277-277
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/scripts/install-apply.test.js` at line 176, The test uses assert.deepStrictEqual on state.resolution.selectedModules which is order-sensitive and brittle; change these assertions (the ones calling assert.deepStrictEqual with state.resolution.selectedModules) to an order-insensitive comparison instead — e.g., compare sorted arrays or compare Sets so membership is asserted regardless of order (replace the deepStrictEqual usage with a sorted-deepStrictEqual or Set-based membership check for state.resolution.selectedModules in both occurrences).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/lib/install-executor.js`:
- Around line 501-531: The createLegacyCompatInstallPlan function accepts
options.claudeRulesDir but does not forward it to createManifestInstallPlan;
update the createManifestInstallPlan call inside createLegacyCompatInstallPlan
to include claudeRulesDir: options.claudeRulesDir (or options.claudeRulesDir ||
undefined) so the provided CLAUDE_RULES_DIR is honored when building the
legacy-compat install plan; reference createLegacyCompatInstallPlan and
createManifestInstallPlan when making this change.
In `@scripts/lib/install/runtime.js`:
- Around line 27-36: The call to createLegacyCompatInstallPlan currently
supplies claudeRulesDir but that parameter is unused downstream; either remove
claudeRulesDir from the argument list in the request.mode === 'legacy-compat'
branch, or (preferred for parity) forward it into the compat plan by updating
createLegacyCompatInstallPlan to accept and pass claudeRulesDir through to
whatever downstream function createLegacyInstallPlan or
createManifestInstallPlan uses; locate the branch keyed by request.mode, adjust
the call site to match createLegacyInstallPlan's signature or update
createLegacyCompatInstallPlan to accept a claudeRulesDir parameter and use it
consistently.
In `@tests/scripts/install-apply.test.js`:
- Around line 316-320: The test "rejects unknown explicit manifest modules
before resolution" currently runs in the real environment; modify it to create
and use a temporary directory as both process cwd and HOME before invoking
run(['--modules', 'ghost-module']) (e.g., by chdir or passing env to run), run
the command there, assert result.code === 1 and stderr contains 'Unknown install
module: ghost-module', then assert that no state file (the project's state file
name used elsewhere in tests) was created in that temp dir, and finally clean
up/reset cwd and HOME; update references in the test body surrounding run(...)
and assertion calls to use the temp dir environment.
---
Nitpick comments:
In `@scripts/lib/install-manifests.js`:
- Around line 235-237: The code calls dedupeStrings twice (on
options.legacyLanguages and then again on legacyLanguages) causing redundant
work; update the logic around dedupeStrings, legacyLanguages, and
normalizedLegacyLanguages so you only deduplicate once and then normalize case
as needed: call dedupeStrings on options.legacyLanguages (or lowercase first
then dedupe if you need case-insensitive results), assign that to
legacyLanguages, then derive normalizedLegacyLanguages without re-calling
dedupeStrings (e.g., map toLowerCase and use a Set or dedupe once), ensuring the
variable names legacyLanguages and normalizedLegacyLanguages reflect the single
deduplication step.
In `@tests/scripts/install-apply.test.js`:
- Line 176: The test uses assert.deepStrictEqual on
state.resolution.selectedModules which is order-sensitive and brittle; change
these assertions (the ones calling assert.deepStrictEqual with
state.resolution.selectedModules) to an order-insensitive comparison instead —
e.g., compare sorted arrays or compare Sets so membership is asserted regardless
of order (replace the deepStrictEqual usage with a sorted-deepStrictEqual or
Set-based membership check for state.resolution.selectedModules in both
occurrences).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e0e29697-6be4-4240-992d-b605d0cfa30f
📒 Files selected for processing (9)
scripts/install-apply.jsscripts/lib/install-executor.jsscripts/lib/install-manifests.jsscripts/lib/install/request.jsscripts/lib/install/runtime.jstests/lib/install-manifests.test.jstests/lib/install-request.test.jstests/scripts/ecc.test.jstests/scripts/install-apply.test.js
| function createLegacyCompatInstallPlan(options = {}) { | ||
| const sourceRoot = options.sourceRoot || getSourceRoot(); | ||
| const projectRoot = options.projectRoot || process.cwd(); | ||
| const target = options.target || 'claude'; | ||
|
|
||
| validateLegacyTarget(target); | ||
|
|
||
| const selection = resolveLegacyCompatibilitySelection({ | ||
| repoRoot: sourceRoot, | ||
| target, | ||
| legacyLanguages: options.legacyLanguages || [], | ||
| }); | ||
|
|
||
| return createManifestInstallPlan({ | ||
| sourceRoot, | ||
| projectRoot, | ||
| homeDir: options.homeDir, | ||
| target, | ||
| profileId: null, | ||
| moduleIds: selection.moduleIds, | ||
| includeComponentIds: [], | ||
| excludeComponentIds: [], | ||
| legacyLanguages: selection.legacyLanguages, | ||
| legacyMode: true, | ||
| requestProfileId: null, | ||
| requestModuleIds: [], | ||
| requestIncludeComponentIds: [], | ||
| requestExcludeComponentIds: [], | ||
| mode: 'legacy-compat', | ||
| }); | ||
| } |
There was a problem hiding this comment.
claudeRulesDir option is accepted but not forwarded to createManifestInstallPlan.
The function accepts options.claudeRulesDir (documented by the caller in runtime.js) but does not pass it to createManifestInstallPlan. If a user sets CLAUDE_RULES_DIR expecting custom rules directory support, the legacy-compat path will silently ignore it.
🔧 Proposed fix to forward claudeRulesDir
return createManifestInstallPlan({
sourceRoot,
projectRoot,
homeDir: options.homeDir,
+ claudeRulesDir: options.claudeRulesDir,
target,
profileId: null,
moduleIds: selection.moduleIds,#!/bin/bash
# Check if createManifestInstallPlan accepts claudeRulesDir
rg -n 'claudeRulesDir' scripts/lib/install-executor.js🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/lib/install-executor.js` around lines 501 - 531, The
createLegacyCompatInstallPlan function accepts options.claudeRulesDir but does
not forward it to createManifestInstallPlan; update the
createManifestInstallPlan call inside createLegacyCompatInstallPlan to include
claudeRulesDir: options.claudeRulesDir (or options.claudeRulesDir || undefined)
so the provided CLAUDE_RULES_DIR is honored when building the legacy-compat
install plan; reference createLegacyCompatInstallPlan and
createManifestInstallPlan when making this change.
| if (request.mode === 'legacy-compat') { | ||
| return createLegacyCompatInstallPlan({ | ||
| target: request.target, | ||
| legacyLanguages: request.legacyLanguages, | ||
| projectRoot: options.projectRoot, | ||
| homeDir: options.homeDir, | ||
| claudeRulesDir: options.claudeRulesDir, | ||
| sourceRoot: options.sourceRoot, | ||
| }); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify createLegacyCompatInstallPlan does not use claudeRulesDir
rg -n -A 30 'function createLegacyCompatInstallPlan' scripts/lib/install-executor.js | head -40Repository: affaan-m/everything-claude-code
Length of output: 1065
🏁 Script executed:
# Check if createManifestInstallPlan accepts claudeRulesDir
rg -n -B 5 'function createManifestInstallPlan' scripts/lib/install-executor.js | head -20Repository: affaan-m/everything-claude-code
Length of output: 202
🏁 Script executed:
# Check the non-legacy path around line 38-47 in runtime.js to see how it handles claudeRulesDir
sed -n '27,50p' scripts/lib/install/runtime.jsRepository: affaan-m/everything-claude-code
Length of output: 787
🏁 Script executed:
# Get full createManifestInstallPlan function signature and first 50 lines to see parameters
sed -n '570,620p' scripts/lib/install-executor.jsRepository: affaan-m/everything-claude-code
Length of output: 2339
🏁 Script executed:
# Check createLegacyInstallPlan to see if it uses claudeRulesDir
rg -n -A 20 'function createLegacyInstallPlan' scripts/lib/install-executor.jsRepository: affaan-m/everything-claude-code
Length of output: 858
Remove unused claudeRulesDir parameter or pass it through to downstream functions.
claudeRulesDir is passed to createLegacyCompatInstallPlan but is never extracted or used within the function. In contrast, createLegacyInstallPlan (the non-compat legacy path) properly extracts and uses this parameter. This inconsistency creates a misleading API and could cause bugs if custom rules directories are configured.
Either pass claudeRulesDir to createManifestInstallPlan for consistency, or remove the parameter from the call site if legacy-compat mode intentionally does not support custom rules directories.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/lib/install/runtime.js` around lines 27 - 36, The call to
createLegacyCompatInstallPlan currently supplies claudeRulesDir but that
parameter is unused downstream; either remove claudeRulesDir from the argument
list in the request.mode === 'legacy-compat' branch, or (preferred for parity)
forward it into the compat plan by updating createLegacyCompatInstallPlan to
accept and pass claudeRulesDir through to whatever downstream function
createLegacyInstallPlan or createManifestInstallPlan uses; locate the branch
keyed by request.mode, adjust the call site to match createLegacyInstallPlan's
signature or update createLegacyCompatInstallPlan to accept a claudeRulesDir
parameter and use it consistently.
| if (test('rejects unknown explicit manifest modules before resolution', () => { | ||
| const result = run(['--modules', 'ghost-module']); | ||
| assert.strictEqual(result.code, 1); | ||
| assert.ok(result.stderr.includes('Unknown install module: ghost-module')); | ||
| })) passed++; else failed++; |
There was a problem hiding this comment.
Isolate the unknown-module failure test from real environment paths.
This case currently runs without temp cwd/HOME. If failure timing regresses, the test can write into the invoking environment. Run it in temp dirs and assert no state file was created.
🧪 Suggested fix
- if (test('rejects unknown explicit manifest modules before resolution', () => {
- const result = run(['--modules', 'ghost-module']);
- assert.strictEqual(result.code, 1);
- assert.ok(result.stderr.includes('Unknown install module: ghost-module'));
- })) passed++; else failed++;
+ if (test('rejects unknown explicit manifest modules before resolution', () => {
+ const homeDir = createTempDir('install-apply-home-');
+ const projectDir = createTempDir('install-apply-project-');
+
+ try {
+ const result = run(['--modules', 'ghost-module'], { cwd: projectDir, homeDir });
+ assert.strictEqual(result.code, 1);
+ assert.ok(result.stderr.includes('Unknown install module: ghost-module'));
+ assert.ok(!fs.existsSync(path.join(homeDir, '.claude', 'ecc', 'install-state.json')));
+ assert.ok(!fs.existsSync(path.join(projectDir, '.cursor', 'ecc-install-state.json')));
+ } finally {
+ cleanup(homeDir);
+ cleanup(projectDir);
+ }
+ })) passed++; else failed++;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/scripts/install-apply.test.js` around lines 316 - 320, The test
"rejects unknown explicit manifest modules before resolution" currently runs in
the real environment; modify it to create and use a temporary directory as both
process cwd and HOME before invoking run(['--modules', 'ghost-module']) (e.g.,
by chdir or passing env to run), run the command there, assert result.code === 1
and stderr contains 'Unknown install module: ghost-module', then assert that no
state file (the project's state file name used elsewhere in tests) was created
in that temp dir, and finally clean up/reset cwd and HOME; update references in
the test body surrounding run(...) and assertion calls to use the temp dir
environment.
There was a problem hiding this comment.
1 issue found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/lib/install-manifests.js">
<violation number="1" location="scripts/lib/install-manifests.js:376">
P1: Skipping a module due to an incompatible dependency can still leave earlier dependencies selected, producing orphan installs from a tree that should have been skipped.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| moduleId, | ||
| rootRequesterId || moduleId | ||
| ); | ||
| if (!dependencyResolved) { |
There was a problem hiding this comment.
P1: Skipping a module due to an incompatible dependency can still leave earlier dependencies selected, producing orphan installs from a tree that should have been skipped.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/lib/install-manifests.js, line 376:
<comment>Skipping a module due to an incompatible dependency can still leave earlier dependencies selected, producing orphan installs from a tree that should have been skipped.</comment>
<file context>
@@ -248,15 +368,27 @@ function resolveInstallPlan(options = {}) {
+ moduleId,
+ rootRequesterId || moduleId
+ );
+ if (!dependencyResolved) {
+ visitingIds.delete(moduleId);
+ if (!dependencyOf) {
</file context>
Summary
scripts/lib/install-manifests.jsresolution into the realscripts/install-apply.jsexecution flow so--profile <name>works end-to-end--modules <id,id,...>parsing and validation in the installermode: 'legacy-compat'withlegacyLanguages, then translate them into manifest-backed module selectionsantigravityIssues
Testing
node tests/run-all.jsSummary by cubic
Wires manifest resolution into the installer so
--profileand manifest-backed--modulesexecute end-to-end, and adds a legacy compatibility flow that maps language installs to manifest modules with target-safe skipping. Closes #463, #464, #465.New Features
scripts/install-apply.jsviainstall-executor.--modules <id,id,...>with dedupe and catalog validation.mode: 'legacy-compat'withlegacyLanguages, resolving to manifest modules (e.g.,golang→go) and target-specific base sets.antigravity.listLegacyCompatibilityLanguages,resolveLegacyCompatibilitySelection,validateInstallModuleIds,createLegacyCompatInstallPlan; expanded CLI and unit tests.Migration
--profile,--modules,--with, or--without(now a hard error).mode: 'legacy-compat'andlegacyLanguages.Written for commit b320fb3. Summary will update on new commits.
Summary by CodeRabbit
Release Notes
New Features
Improvements