Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compat/aiox-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aiox-core",
"version": "5.2.2",
"version": "5.2.3",
"description": "Compatibility wrapper for @aiox-squads/core.",
"license": "MIT",
"bin": {
Expand All @@ -15,7 +15,7 @@
"README.md"
],
"dependencies": {
"@aiox-squads/core": "5.2.2"
"@aiox-squads/core": "5.2.3"
},
"engines": {
"node": ">=18"
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aiox-squads/core",
"version": "5.2.2",
"version": "5.2.3",
"description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework",
"bin": {
"aiox": "bin/aiox.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/installer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aiox-squads/installer",
"version": "3.3.2",
"version": "3.3.3",
"description": "AIOX Installer - Automated setup wizard for AIOX projects (greenfield & brownfield)",
"main": "src/index.js",
"bin": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ async function validateDependencies(depsContext = {}) {
// Check node_modules existence
const nodeModulesPath = path.join(projectRoot, 'node_modules');
const packageJsonPath = path.join(projectRoot, 'package.json');
const packageJsonExists = fs.existsSync(packageJsonPath);
const isGreenfieldNoPackageJson =
depsContext.skipped === true &&
depsContext.reason === 'no-package-json' &&
!packageJsonExists;

// For greenfield projects, check if package.json has dependencies
let hasDependencies = false;
if (fs.existsSync(packageJsonPath)) {
if (packageJsonExists) {
try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
hasDependencies = !!(
Expand Down Expand Up @@ -92,14 +97,31 @@ async function validateDependencies(depsContext = {}) {
message: 'Directory exists',
});

// Validate package.json integrity
await validatePackageJson(results, projectRoot);
if (isGreenfieldNoPackageJson) {
results.checks.push({
component: 'Package Manifest',
file: packageJsonPath,
status: 'skipped',
message: 'No package.json found (greenfield project)',
});
} else {
// Validate package.json integrity
await validatePackageJson(results, projectRoot);
}

// Validate any explicit dependency contract supplied by the caller.
await checkRequiredDependencies(results, projectRoot, depsContext.requiredDependencies);

// Run npm audit (non-blocking - warnings only)
await runSecurityAudit(results, depsContext.packageManager, projectRoot);
if (isGreenfieldNoPackageJson) {
results.checks.push({
component: 'Security Audit',
status: 'skipped',
message: 'No package.json found (greenfield project)',
});
} else {
// Run npm audit (non-blocking - warnings only)
await runSecurityAudit(results, depsContext.packageManager, projectRoot);
}

// Count installed packages
await countInstalledPackages(results, nodeModulesPath);
Expand Down
39 changes: 39 additions & 0 deletions tests/unit/wizard/validation/dependency-validator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,45 @@ describe('Dependency Validator', () => {
);
});

it('does not fail greenfield validation when Pro creates node_modules without package.json', async () => {
const projectPath = '/tmp/aiox-greenfield-pro';

fs.existsSync.mockImplementation((targetPath) => (
samePath(targetPath, projectFile(projectPath, 'node_modules'))
));
fs.readdirSync.mockReturnValue(['@aiox-squads', '.bin']);

const result = await validateDependencies({
success: true,
skipped: true,
reason: 'no-package-json',
packageManager: 'npm',
projectPath,
});

expect(result.success).toBe(true);
expect(result.errors).toEqual([]);
expect(result.checks).toEqual(
expect.arrayContaining([
expect.objectContaining({
component: 'Dependencies',
status: 'success',
}),
expect.objectContaining({
component: 'Package Manifest',
status: 'skipped',
message: 'No package.json found (greenfield project)',
}),
expect.objectContaining({
component: 'Security Audit',
status: 'skipped',
message: 'No package.json found (greenfield project)',
}),
]),
);
expect(childProcess.exec).not.toHaveBeenCalled();
});

it('fails when package.json declares dependencies but node_modules is missing', async () => {
const projectPath = '/tmp/aiox-broken';

Expand Down
Loading