Skip to content

feat(enterprise): add Pro upgrade pipeline#704

Merged
rafaelscosta merged 2 commits intomainfrom
feature/pro-enterprise-upgrade-cli-20260508
May 8, 2026
Merged

feat(enterprise): add Pro upgrade pipeline#704
rafaelscosta merged 2 commits intomainfrom
feature/pro-enterprise-upgrade-cli-20260508

Conversation

@rafaelscosta
Copy link
Copy Markdown
Collaborator

@rafaelscosta rafaelscosta commented May 8, 2026

Summary

  • Adds aiox enterprise upgrade dry-run/apply/rollback CLI for Core + Pro to Enterprise migrations.
  • Adds manifest-driven allow/preserve/deny policy, transactional backups, execution manifest, and rollback support.
  • Adds Enterprise detector, manifest loader/schema, plan/apply engine, package exports, unit coverage, and E2E smoke coverage.

Boundary

  • Core/Pro ships only the CLI substrate and upgrade engine.
  • The migration skill is intentionally not distributed from Core/Pro; it lives in the AIOX Enterprise repo.

Validation

  • PASS: npm run test:e2e:pro-enterprise-upgrade
  • PASS: npm test -- packages/installer/tests/unit/enterprise --runInBand
  • PASS: focused ESLint on changed files
  • PASS: npm run typecheck
  • PASS: npm run lint (0 errors; 3 existing warnings in tests/ide-sync/kimi-transformer.test.js)
  • GLOBAL: npm test -- --runInBand completed with one timing threshold failure in tests/unit/squad/squad-loader.test.js (126ms vs 100ms); isolated rerun passed (32/32). Jest held an open handle after summary and was terminated after output was captured.

Summary by CodeRabbit

  • New Features

    • Added enterprise upgrade CLI to plan and apply migrations from Pro to Enterprise, with --dry-run/--apply, --enterprise-source, and --plan output.
    • Dry-run plan serialization (YAML/JSON) and writable plan file.
    • Transactional apply with backups, execution manifest, and rollback support.
    • Entitlement checks and optional test-fixture bypass; captures doctor output during apply.
  • Documentation

    • Help text documents enterprise upgrade usage and examples.
  • Tests

    • Unit and end-to-end tests and a smoke script covering planning, apply, and rollback.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aiox-core Ready Ready Preview, Comment May 8, 2026 4:32pm

Request Review

@github-actions github-actions Bot added area: agents Agent system related area: workflows Workflow system related squad mcp type: test Test coverage and quality area: core Core framework (.aios-core/core/) area: installer Installer and setup (packages/installer/) area: synapse SYNAPSE context engine area: cli CLI tools (bin/, packages/aios-pro-cli/) area: pro Pro features (pro/) area: health-check Health check system area: docs Documentation (docs/) area: devops CI/CD, GitHub Actions (.github/) labels May 8, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8bfe7fc4-d129-4e8e-ab41-122c7ff0704b

📥 Commits

Reviewing files that changed from the base of the PR and between fbc2c79 and 946bb77.

📒 Files selected for processing (8)
  • bin/aiox.js
  • packages/installer/src/enterprise/enterprise-rollback.js
  • packages/installer/src/enterprise/enterprise-upgrade-plan.js
  • packages/installer/src/enterprise/enterprise-upgrader.js
  • packages/installer/src/enterprise/enterprise-utils.js
  • packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js
  • packages/installer/tests/unit/enterprise/enterprise-upgrader.test.js
  • scripts/e2e/pro-to-enterprise-upgrade-smoke.js
✅ Files skipped from review due to trivial changes (1)
  • packages/installer/src/enterprise/enterprise-utils.js
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/installer/tests/unit/enterprise/enterprise-upgrader.test.js
  • packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js
  • packages/installer/src/enterprise/enterprise-rollback.js
  • packages/installer/src/enterprise/enterprise-upgrader.js
  • packages/installer/src/enterprise/enterprise-upgrade-plan.js
  • bin/aiox.js
  • scripts/e2e/pro-to-enterprise-upgrade-smoke.js

Walkthrough

Adds a full Enterprise upgrade subsystem: manifest schema and loader, detection of Core/Pro/Enterprise installs, plan generation and CLI, transactional upgrader with backups and rollback, utilities, unit tests, and an end-to-end smoke test.

Changes

Enterprise Upgrade System

Layer / File(s) Summary
Schema & Error Types
packages/installer/src/enterprise/enterprise-upgrade-manifest.schema.json, packages/installer/src/enterprise/enterprise-upgrade-manifest.yaml, packages/installer/src/enterprise/enterprise-errors.js
Adds JSON Schema and manifest YAML for enterprise upgrade policy; introduces EnterpriseUpgradeError.
Installation Detection
packages/installer/src/enterprise/enterprise-detector.js
Detects Core/Pro/Enterprise installs and active IDE surfaces using multiple filesystem and package markers; normalizes portable paths.
Manifest Loading & Validation
packages/installer/src/enterprise/enterprise-manifest-loader.js
Loads YAML manifest, validates with AJV, converts glob patterns to RegExp, resolves migration policies (blockedPaths precedence), and derives preserved/candidate/blocked operation lists.
Plan Generation & CLI
packages/installer/src/enterprise/enterprise-upgrade-plan.js
Normalizes options, validates context, builds upgrade plans (dry-run/apply), serializes YAML/JSON, parses CLI args, and implements runEnterpriseUpgradeCli.
Execution, Utils & Rollback
packages/installer/src/enterprise/enterprise-upgrader.js, packages/installer/src/enterprise/enterprise-utils.js, packages/installer/src/enterprise/enterprise-rollback.js
Implements apply policies (preserve, copy-if-missing, hash-overwrite-with-backup, merge-yaml), recording/backing up files, sha256 helper, execution manifest writing, and rollback that restores backed-up files.
CLI Integration & Exports
bin/aiox.js, package.json
Adds enterprise command and examples to CLI help; adds runEnterprise() wiring in bin/aiox.js; exposes new installer enterprise entry points and e2e npm script in package.json.
Unit Tests
packages/installer/tests/unit/enterprise/*
Jest suites covering manifest loading, policy precedence, plan generation, upgrader behaviors, entitlement gating, rollback, and CLI invocation.
E2E Smoke Test
scripts/e2e/pro-to-enterprise-upgrade-smoke.js
End-to-end smoke test: fixture provisioning, plan generation, apply with test entitlement, execution manifest assertions, filesystem checks, and rollback verification.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as bin/aiox.js
  participant Plan as enterprise-upgrade-plan
  participant Upgrader as enterprise-upgrader
  participant FS as filesystem
  User->>CLI: aiox enterprise upgrade --enterprise-source ...
  CLI->>Plan: runEnterpriseUpgradeCli(argv)
  Plan-->>User: plan (dry-run) or writes plan file
  User->>CLI: aiox enterprise upgrade --apply --enterprise-source ...
  CLI->>Upgrader: applyEnterpriseUpgrade(plan, options)
  Upgrader->>FS: expand source, backup files, write files, write execution manifest
  User->>CLI: aiox enterprise upgrade rollback --manifest ...
  CLI->>Upgrader: rollbackEnterpriseUpgrade(manifest)
  Upgrader->>FS: restore backed-up files, write rollback manifest
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested Reviewers

  • oalanicolas
  • Pedrovaleriolopez
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(enterprise): add Pro upgrade pipeline' clearly describes the main change: adding an enterprise upgrade feature with a Pro upgrade pipeline, which aligns with the PR's core objective of introducing the aiox enterprise upgrade CLI supporting dry-run, apply, and rollback flows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/pro-enterprise-upgrade-cli-20260508

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

📊 Coverage Report

Coverage report not available

📈 Full coverage report available in Codecov


Generated by PR Automation (Story 6.1)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js (1)

8-12: 💤 Low value

Same absolute-import guideline applies here.

The same relative-import note flagged on enterprise-upgrader.test.js applies — '../../../src/enterprise/enterprise-upgrade-plan' can be replaced with '@aiox-squads/core/installer/enterprise-upgrade-plan' per the project's coding guideline. Defer until convention is confirmed across the test tree.

As per coding guidelines: "Use absolute imports instead of relative imports in all code".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js`
around lines 8 - 12, Replace the relative import of
'../../../src/enterprise/enterprise-upgrade-plan' with the project-standard
absolute module import '@aiox-squads/core/installer/enterprise-upgrade-plan' so
tests import buildEnterpriseUpgradePlan, runEnterpriseUpgradeCli, and
writeEnterpriseUpgradePlan via the absolute path; update the require statement
in enterprise-upgrade-plan.test.js to use that module name to comply with the
absolute-import guideline.
bin/aiox.js (1)

78-79: 💤 Low value

Optional: harmonize --target mention across help blocks.

The top USAGE block (lines 78-79) shows --dry-run --enterprise-source <path> while the ENTERPRISE section (lines 116-117) consistently leads with --target .. Since --target defaults to cwd this isn't incorrect, but a one-line tweak in USAGE would prevent users from missing the flag.

Also applies to: 115-118

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/aiox.js` around lines 78 - 79, Update the USAGE help string that
currently reads "npx aiox-core@latest enterprise upgrade --dry-run
--enterprise-source <path>" to include the --target flag (e.g., "--target
<path|.>") or note its default, matching the ENTERPRISE section which leads with
"--target ."; locate and edit the string in the help generation for the
enterprise upgrade command (the literal command line shown) so both USAGE and
the ENTERPRISE section consistently mention --target to avoid confusion.
packages/installer/src/enterprise/enterprise-upgrader.js (1)

265-297: 💤 Low value

sha256File(destPath) called twice on the merged result in applyMergeYaml

Line 289 and line 295 both call sha256File(destPath) after the YAML write; nothing changes between the two calls so the results are always identical. Cache the hash from the first call.

♻️ Proposed fix
-  executionManifest.merged.push({
+  const mergedHash = sha256File(destPath);
+  executionManifest.merged.push({
     path: relativePath,
     policy: 'merge-yaml',
-    sha256: sha256File(destPath),
+    sha256: mergedHash,
     backedUp: existed,
   });
   executionManifest.validated.push({
     path: relativePath,
     type: 'exists',
-    sha256: sha256File(destPath),
+    sha256: mergedHash,
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/installer/src/enterprise/enterprise-upgrader.js` around lines 265 -
297, applyMergeYaml currently calls sha256File(destPath) twice after writeYaml;
compute the hash once and reuse it to avoid redundant work. After
writeYaml(destPath, merged) call sha256File(destPath) one time (e.g., const sha
= sha256File(destPath)) and replace both sha256File(destPath) occurrences in
executionManifest.merged and executionManifest.validated with that cached
variable; keep the rest of applyMergeYaml logic unchanged.
packages/installer/src/enterprise/enterprise-rollback.js (1)

7-7: ⚡ Quick win

Extract sha256File to a shared utility to break the cross-module coupling

enterprise-rollback.js imports a single hashing utility from enterprise-upgrader.js. enterprise-upgrader.js in turn imports from enterprise-upgrade-plan.js, which dynamically requires enterprise-rollback.js at runtime. This creates a fragile load-order dependency: any future top-level import of enterprise-rollback inside enterprise-upgrade-plan would form a real circular dependency. Moving sha256File (and optionally nowStamp) to an enterprise-utils.js file removes this risk with minimal churn.

♻️ Proposed refactor

New file packages/installer/src/enterprise/enterprise-utils.js:

'use strict';

const crypto = require('crypto');
const fs = require('fs-extra');

function sha256File(filePath) {
  return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
}

module.exports = { sha256File };

Then in enterprise-rollback.js:

-const { sha256File } = require('./enterprise-upgrader');
+const { sha256File } = require('./enterprise-utils');

And in enterprise-upgrader.js:

-function sha256File(filePath) { ... }
+const { sha256File } = require('./enterprise-utils');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/installer/src/enterprise/enterprise-rollback.js` at line 7, The
import of sha256File in enterprise-rollback.js creates a fragile load-order
coupling with enterprise-upgrader.js/enterprise-upgrade-plan.js; extract
sha256File (and optionally nowStamp) into a new shared module named
enterprise-utils.js that exports sha256File, then update enterprise-rollback.js
and enterprise-upgrader.js to require './enterprise-utils' instead of requiring
across modules; ensure the new sha256File implementation uses crypto and
fs-extra as in the proposal and remove the original sha256File definition/import
from enterprise-upgrader.js so the circular load dependency is eliminated.
scripts/e2e/pro-to-enterprise-upgrade-smoke.js (1)

148-148: 💤 Low value

async on main() is unnecessary

No await expression exists anywhere in the function body; all operations are synchronous. The async modifier only adds a Promise wrapper that the .catch() at line 227 consumes. A plain synchronous function with a top-level try/catch would be clearer.

♻️ Proposed refactor
-async function main() {
+function main() {
   try {
     ...
   } finally {
     cleanup();
   }
 }
 
-main().catch((error) => {
+try {
+  main();
+} catch (error) {
   console.error(`[pro-enterprise-e2e] FAIL: ${error.message}`);
   process.exit(1);
-});
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e/pro-to-enterprise-upgrade-smoke.js` at line 148, The function
declaration async function main() has no await usages; remove the async modifier
(make it function main()) and convert the top-level .catch() invocation into a
plain try/catch around the synchronous call: call main() inside try { main(); }
catch (err) { /* reuse existing error handling logic */ } so that error handling
remains but the unnecessary Promise wrapper is eliminated; update references to
main() and the existing .catch() chain accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/installer/src/enterprise/enterprise-upgrade-plan.js`:
- Around line 203-233: parseEnterpriseUpgradeArgs currently assigns argv[index +
1] to flags that expect values without checking that a value exists or isn't
another flag; update the parsing for '--target', '--enterprise-source',
'--manifest', '--plan', and '--format' so that before setting
options.targetDir/options.enterpriseSource/options.manifestPath/options.planPath/options.format
you verify argv[index + 1] exists and does not start with '-' (i.e., is not
another flag); if the guard fails, throw an EnterpriseUpgradeError indicating a
missing value for that specific option instead of consuming the next flag as the
value.
- Line 44: The warning string is stale and is always added by buildWarnings
(called from buildEnterpriseUpgradePlan and applyEnterpriseUpgrade), so update
buildWarnings to only push "Dry-run only: apply, rollback, and validation policy
are implemented in later slices." when the invocation is actually a dry-run (or
when a flag like options.mode === 'dry-run' or options.dryRun is true); locate
and modify buildWarnings (and any caller that builds options passed into it,
e.g., buildEnterpriseUpgradePlan and applyEnterpriseUpgrade) so they pass the
current mode/flag and the warning is conditionally appended rather than
unconditionally pushed.

In `@packages/installer/src/enterprise/enterprise-upgrader.js`:
- Around line 44-63: mergeDeep currently returns target when either side is an
array, which silently drops enterprise array values; change array handling in
mergeDeep to perform a union merge when both source and target are arrays
(preserve existing target items and append any source items not already
present), e.g., detect Array.isArray(source) && Array.isArray(target) and return
a deduplicated concatenation that keeps target order, while keeping the existing
behavior for when only one side is an array (return the defined side); update
mergeDeep (function name) so array-merge happens before the early return that
currently returns target unconditionally.

---

Nitpick comments:
In `@bin/aiox.js`:
- Around line 78-79: Update the USAGE help string that currently reads "npx
aiox-core@latest enterprise upgrade --dry-run --enterprise-source <path>" to
include the --target flag (e.g., "--target <path|.>") or note its default,
matching the ENTERPRISE section which leads with "--target ."; locate and edit
the string in the help generation for the enterprise upgrade command (the
literal command line shown) so both USAGE and the ENTERPRISE section
consistently mention --target to avoid confusion.

In `@packages/installer/src/enterprise/enterprise-rollback.js`:
- Line 7: The import of sha256File in enterprise-rollback.js creates a fragile
load-order coupling with enterprise-upgrader.js/enterprise-upgrade-plan.js;
extract sha256File (and optionally nowStamp) into a new shared module named
enterprise-utils.js that exports sha256File, then update enterprise-rollback.js
and enterprise-upgrader.js to require './enterprise-utils' instead of requiring
across modules; ensure the new sha256File implementation uses crypto and
fs-extra as in the proposal and remove the original sha256File definition/import
from enterprise-upgrader.js so the circular load dependency is eliminated.

In `@packages/installer/src/enterprise/enterprise-upgrader.js`:
- Around line 265-297: applyMergeYaml currently calls sha256File(destPath) twice
after writeYaml; compute the hash once and reuse it to avoid redundant work.
After writeYaml(destPath, merged) call sha256File(destPath) one time (e.g.,
const sha = sha256File(destPath)) and replace both sha256File(destPath)
occurrences in executionManifest.merged and executionManifest.validated with
that cached variable; keep the rest of applyMergeYaml logic unchanged.

In `@packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js`:
- Around line 8-12: Replace the relative import of
'../../../src/enterprise/enterprise-upgrade-plan' with the project-standard
absolute module import '@aiox-squads/core/installer/enterprise-upgrade-plan' so
tests import buildEnterpriseUpgradePlan, runEnterpriseUpgradeCli, and
writeEnterpriseUpgradePlan via the absolute path; update the require statement
in enterprise-upgrade-plan.test.js to use that module name to comply with the
absolute-import guideline.

In `@scripts/e2e/pro-to-enterprise-upgrade-smoke.js`:
- Line 148: The function declaration async function main() has no await usages;
remove the async modifier (make it function main()) and convert the top-level
.catch() invocation into a plain try/catch around the synchronous call: call
main() inside try { main(); } catch (err) { /* reuse existing error handling
logic */ } so that error handling remains but the unnecessary Promise wrapper is
eliminated; update references to main() and the existing .catch() chain
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dca13969-1bf6-4232-8d4b-5e2d1f586898

📥 Commits

Reviewing files that changed from the base of the PR and between 106bb34 and fbc2c79.

📒 Files selected for processing (14)
  • bin/aiox.js
  • package.json
  • packages/installer/src/enterprise/enterprise-detector.js
  • packages/installer/src/enterprise/enterprise-errors.js
  • packages/installer/src/enterprise/enterprise-manifest-loader.js
  • packages/installer/src/enterprise/enterprise-rollback.js
  • packages/installer/src/enterprise/enterprise-upgrade-manifest.schema.json
  • packages/installer/src/enterprise/enterprise-upgrade-manifest.yaml
  • packages/installer/src/enterprise/enterprise-upgrade-plan.js
  • packages/installer/src/enterprise/enterprise-upgrader.js
  • packages/installer/tests/unit/enterprise/enterprise-manifest-loader.test.js
  • packages/installer/tests/unit/enterprise/enterprise-upgrade-plan.test.js
  • packages/installer/tests/unit/enterprise/enterprise-upgrader.test.js
  • scripts/e2e/pro-to-enterprise-upgrade-smoke.js

Comment thread packages/installer/src/enterprise/enterprise-upgrade-plan.js Outdated
Comment thread packages/installer/src/enterprise/enterprise-upgrade-plan.js
Comment thread packages/installer/src/enterprise/enterprise-upgrader.js
@rafaelscosta rafaelscosta merged commit 84cebbd into main May 8, 2026
40 checks passed
@rafaelscosta rafaelscosta deleted the feature/pro-enterprise-upgrade-cli-20260508 branch May 8, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agents Agent system related area: cli CLI tools (bin/, packages/aios-pro-cli/) area: core Core framework (.aios-core/core/) area: devops CI/CD, GitHub Actions (.github/) area: docs Documentation (docs/) area: health-check Health check system area: installer Installer and setup (packages/installer/) area: pro Pro features (pro/) area: synapse SYNAPSE context engine area: workflows Workflow system related mcp squad type: test Test coverage and quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant