aiox-core 5.0.7 → 5.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aiox-core/cli/commands/pro/buyer.js +379 -0
- package/.aiox-core/cli/commands/pro/index.js +191 -52
- package/.aiox-core/cli/commands/validate/index.js +2 -0
- package/.aiox-core/core/code-intel/helpers/dev-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/devops-helper.js +0 -1
- package/.aiox-core/core/code-intel/helpers/planning-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/qa-helper.js +2 -2
- package/.aiox-core/core/config/schemas/framework-config.schema.json +1 -0
- package/.aiox-core/core/config/template-overrides.js +1 -1
- package/.aiox-core/core/doctor/checks/ide-sync.js +81 -25
- package/.aiox-core/core/doctor/checks/rules-files.js +0 -1
- package/.aiox-core/core/doctor/checks/skills-count.js +83 -15
- package/.aiox-core/core/graph-dashboard/cli.js +1 -2
- package/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
- package/.aiox-core/core/ids/layer-classifier.js +1 -1
- package/.aiox-core/core/pro/pro-updater.js +578 -0
- package/.aiox-core/core/synapse/context/context-tracker.js +107 -9
- package/.aiox-core/core/synapse/layers/layer-processor.js +1 -1
- package/.aiox-core/core-config.yaml +15 -1
- package/.aiox-core/data/capability-detection.js +15 -15
- package/.aiox-core/data/entity-registry.yaml +18 -2
- package/.aiox-core/data/registry-update-log.jsonl +5 -0
- package/.aiox-core/data/tok3-token-comparison.js +0 -4
- package/.aiox-core/data/tool-search-validation.js +1 -1
- package/.aiox-core/development/agents/aiox-master.md +44 -6
- package/.aiox-core/development/agents/data-engineer.md +4 -4
- package/.aiox-core/development/agents/devops.md +52 -2
- package/.aiox-core/development/agents/po.md +1 -1
- package/.aiox-core/development/agents/qa.md +5 -11
- package/.aiox-core/development/agents/sm.md +3 -3
- package/.aiox-core/development/agents/ux-design-expert.md +1 -1
- package/.aiox-core/development/scripts/unified-activation-pipeline.js +29 -3
- package/.aiox-core/development/tasks/dev-develop-story.md +46 -7
- package/.aiox-core/development/tasks/devops-pro-access-grant.md +93 -0
- package/.aiox-core/development/tasks/devops-pro-activate.md +42 -0
- package/.aiox-core/development/tasks/devops-pro-check-access.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-request-reset.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-resend-verification.md +32 -0
- package/.aiox-core/development/tasks/devops-pro-reset-password.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-validate-login.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-verify-status.md +33 -0
- package/.aiox-core/development/tasks/qa-gate.md +54 -4
- package/.aiox-core/development/tasks/validate-next-story.md +39 -2
- package/.aiox-core/framework-config.yaml +1 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/README.md +69 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js +727 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/index.js +10 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/validate.js +65 -4
- package/.aiox-core/infrastructure/scripts/generate-settings-json.js +29 -4
- package/.aiox-core/infrastructure/scripts/ide-sync/agent-parser.js +4 -0
- package/.aiox-core/infrastructure/scripts/ide-sync/index.js +67 -7
- package/.aiox-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +145 -3
- package/.aiox-core/infrastructure/scripts/repair-agent-references.js +263 -0
- package/.aiox-core/infrastructure/scripts/validate-claude-integration.js +60 -8
- package/.aiox-core/infrastructure/scripts/validate-paths.js +13 -0
- package/.aiox-core/install-manifest.yaml +134 -82
- package/.aiox-core/utils/filters/index.js +2 -1
- package/.claude/commands/AIOX/agents/aiox-master.md +21 -0
- package/.claude/commands/AIOX/agents/analyst.md +21 -0
- package/.claude/commands/AIOX/agents/architect.md +21 -0
- package/.claude/commands/AIOX/agents/data-engineer.md +21 -0
- package/.claude/commands/AIOX/agents/dev.md +21 -0
- package/.claude/commands/AIOX/agents/devops.md +21 -0
- package/.claude/commands/AIOX/agents/pm.md +21 -0
- package/.claude/commands/AIOX/agents/po.md +21 -0
- package/.claude/commands/AIOX/agents/qa.md +21 -0
- package/.claude/commands/AIOX/agents/sm.md +21 -0
- package/.claude/commands/AIOX/agents/squad-creator.md +21 -0
- package/.claude/commands/AIOX/agents/ux-design-expert.md +21 -0
- package/.claude/commands/AIOX/scripts/agent-config-loader.js +624 -0
- package/.claude/commands/AIOX/scripts/generate-greeting.js +160 -0
- package/.claude/commands/AIOX/scripts/greeting-builder.js +866 -0
- package/.claude/commands/AIOX/scripts/session-context-loader.js +286 -0
- package/.claude/commands/AIOX/stories/story-6.1.4.md +1404 -0
- package/.claude/commands/cohort-squad/agents/cohort-manager.md +156 -0
- package/.claude/commands/design-system/agents/brad-frost.md +1097 -0
- package/.claude/commands/design-system/agents/dan-mall.md +857 -0
- package/.claude/commands/design-system/agents/dave-malouf.md +2272 -0
- package/.claude/commands/design-system/agents/design-chief.md +102 -0
- package/.claude/commands/design-system/agents/nano-banana-generator.md +162 -0
- package/.claude/commands/greet.md +101 -0
- package/.claude/commands/synapse/manager.md +75 -0
- package/.claude/commands/synapse/tasks/add-rule.md +94 -0
- package/.claude/commands/synapse/tasks/create-command.md +109 -0
- package/.claude/commands/synapse/tasks/create-domain.md +127 -0
- package/.claude/commands/synapse/tasks/diagnose-synapse.md +245 -0
- package/.claude/commands/synapse/tasks/edit-rule.md +109 -0
- package/.claude/commands/synapse/tasks/suggest-domain.md +116 -0
- package/.claude/commands/synapse/tasks/toggle-domain.md +83 -0
- package/.claude/commands/synapse/templates/domain-template +8 -0
- package/.claude/commands/synapse/templates/manifest-entry-template +4 -0
- package/.claude/commands/synapse/utils/manifest-parser-reference.md +134 -0
- package/.claude/hooks/precompact-session-digest.cjs +2 -2
- package/.claude/skills/AIOX/agents/aiox-master/SKILL.md +511 -0
- package/.claude/skills/AIOX/agents/analyst/SKILL.md +281 -0
- package/.claude/skills/AIOX/agents/architect/SKILL.md +482 -0
- package/.claude/skills/AIOX/agents/data-engineer/SKILL.md +503 -0
- package/.claude/skills/AIOX/agents/dev/SKILL.md +568 -0
- package/.claude/skills/AIOX/agents/devops/SKILL.md +597 -0
- package/.claude/skills/AIOX/agents/pm/SKILL.md +385 -0
- package/.claude/skills/AIOX/agents/po/SKILL.md +343 -0
- package/.claude/skills/AIOX/agents/qa/SKILL.md +451 -0
- package/.claude/skills/AIOX/agents/sm/SKILL.md +295 -0
- package/.claude/skills/AIOX/agents/squad-creator/SKILL.md +352 -0
- package/.claude/skills/AIOX/agents/ux-design-expert/SKILL.md +503 -0
- package/.claude/skills/architect-first/SKILL.md +275 -0
- package/.claude/skills/architect-first/assets/architecture-template.md +505 -0
- package/.claude/skills/architect-first/assets/config-template.yaml +351 -0
- package/.claude/skills/architect-first/references/architecture-checklist.md +216 -0
- package/.claude/skills/architect-first/references/pre-implementation-checklist.md +119 -0
- package/.claude/skills/architect-first/references/stop-rules-guide.md +291 -0
- package/.claude/skills/architect-first/references/testing-strategy-guide.md +477 -0
- package/.claude/skills/architect-first/scripts/architecture_validator.py +490 -0
- package/.claude/skills/architect-first/scripts/check_coupling.py +306 -0
- package/.claude/skills/architect-first/scripts/validate_risk_mitigation.py +382 -0
- package/.claude/skills/checklist-runner/SKILL.md +113 -0
- package/.claude/skills/clone-mind.md +329 -0
- package/.claude/skills/coderabbit-review/SKILL.md +106 -0
- package/.claude/skills/course-generation-workflow.md +76 -0
- package/.claude/skills/enhance-workflow.md +466 -0
- package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
- package/.claude/skills/mcp-builder/SKILL.md +328 -0
- package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
- package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/.claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/.claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
- package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/.claude/skills/ralph.md +181 -0
- package/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/skill-creator/SKILL.md +209 -0
- package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/.claude/skills/squad.md +301 -0
- package/.claude/skills/synapse/SKILL.md +132 -0
- package/.claude/skills/synapse/assets/README.md +50 -0
- package/.claude/skills/synapse/references/brackets.md +100 -0
- package/.claude/skills/synapse/references/commands.md +118 -0
- package/.claude/skills/synapse/references/domains.md +126 -0
- package/.claude/skills/synapse/references/layers.md +186 -0
- package/.claude/skills/synapse/references/manifest.md +142 -0
- package/.claude/skills/tech-search/SKILL.md +431 -0
- package/.claude/skills/tech-search/prompts/page-extract.md +133 -0
- package/README.en.md +2 -2
- package/README.md +8 -2
- package/bin/aiox.js +55 -4
- package/bin/utils/framework-guard.js +4 -2
- package/bin/utils/pro-detector.js +119 -28
- package/bin/utils/validate-publish.js +6 -6
- package/docs/aiox-agent-flows/devops-system.md +18 -0
- package/docs/aiox-workflows/README.md +1 -0
- package/docs/aiox-workflows/pro-access-grant-workflow.md +218 -0
- package/docs/guides/pro/access-grant-ops-playbook.md +370 -0
- package/docs/guides/pro/install-gate-setup.md +12 -6
- package/docs/guides/pro/squad-creator-handoff-pro-access-ops.md +134 -0
- package/docs/guides/supabase-ops-handoff.md +768 -0
- package/package.json +12 -1
- package/packages/aiox-pro-cli/bin/aiox-pro.js +33 -12
- package/packages/installer/src/config/configure-environment.js +118 -50
- package/packages/installer/src/installer/aiox-core-installer.js +124 -27
- package/packages/installer/src/installer/brownfield-upgrader.js +66 -9
- package/packages/installer/src/installer/dependency-installer.js +4 -0
- package/packages/installer/src/pro/pro-scaffolder.js +5 -5
- package/packages/installer/src/updater/index.js +151 -10
- package/packages/installer/src/wizard/ide-config-generator.js +73 -7
- package/packages/installer/src/wizard/index.js +119 -31
- package/packages/installer/src/wizard/pro-setup.js +118 -47
- package/packages/installer/src/wizard/validation/validators/dependency-validator.js +32 -25
- package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +26 -0
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +84 -1
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +1 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +85 -19
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +4 -4
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +5 -5
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +4 -4
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +11 -11
- package/pro/README.md +12 -1
- package/pro/license/index.js +3 -11
- package/pro/license/license-api.js +25 -0
- package/pro/license/license-cache.js +135 -31
- package/pro/license/license-crypto.js +59 -3
- package/pro/package.json +5 -4
- package/pro/squads/README.md +16 -16
- package/pro/squads/index.js +1 -1
- package/scripts/e2e/installed-skills-smoke.js +264 -0
- package/scripts/package-synapse.js +3 -3
- package/scripts/validate-package-completeness.js +8 -11
- package/.aiox-core/lib/build.json +0 -1
|
@@ -22,7 +22,13 @@ const {
|
|
|
22
22
|
const { setLanguage, t } = require('./i18n');
|
|
23
23
|
const yaml = require('js-yaml');
|
|
24
24
|
const { showWelcome, showCompletion, showCancellation } = require('./feedback');
|
|
25
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
generateIDEConfigs,
|
|
27
|
+
showSuccessSummary,
|
|
28
|
+
copySkillFiles,
|
|
29
|
+
generateCodexSkills,
|
|
30
|
+
copyExtraCommandFiles,
|
|
31
|
+
} = require('./ide-config-generator');
|
|
26
32
|
const {
|
|
27
33
|
configureEnvironment,
|
|
28
34
|
} = require('../config/configure-environment');
|
|
@@ -30,6 +36,7 @@ const {
|
|
|
30
36
|
installDependencies,
|
|
31
37
|
} = require('../installer/dependency-installer');
|
|
32
38
|
const { commandSync, commandValidate } = require('../../../../.aiox-core/infrastructure/scripts/ide-sync/index');
|
|
39
|
+
const { syncSkills: syncCodexSkills } = require('../../../../.aiox-core/infrastructure/scripts/codex-skills-sync/index');
|
|
33
40
|
const {
|
|
34
41
|
installAioxCore,
|
|
35
42
|
hasPackageJson,
|
|
@@ -329,12 +336,43 @@ async function runWizard(options = {}) {
|
|
|
329
336
|
}
|
|
330
337
|
}
|
|
331
338
|
|
|
339
|
+
if (options.dryRun) {
|
|
340
|
+
const preview = {
|
|
341
|
+
dryRun: true,
|
|
342
|
+
projectType: answers.projectType,
|
|
343
|
+
selectedIDEs: answers.selectedIDEs || [],
|
|
344
|
+
selectedTechPreset: answers.selectedTechPreset || 'none',
|
|
345
|
+
steps: [
|
|
346
|
+
'install-aiox-core',
|
|
347
|
+
'generate-ide-configs',
|
|
348
|
+
'generate-boundary-rules',
|
|
349
|
+
'copy-skills-and-commands',
|
|
350
|
+
'run-ide-sync',
|
|
351
|
+
'bootstrap-entity-registry',
|
|
352
|
+
'configure-environment',
|
|
353
|
+
'install-dependencies',
|
|
354
|
+
'validate-installation',
|
|
355
|
+
],
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
if (!options.quiet) {
|
|
359
|
+
console.log('\n🧪 Dry run mode');
|
|
360
|
+
console.log(' No files will be modified.');
|
|
361
|
+
console.log(` Project type: ${preview.projectType}`);
|
|
362
|
+
console.log(` IDEs: ${preview.selectedIDEs.length > 0 ? preview.selectedIDEs.join(', ') : 'none'}`);
|
|
363
|
+
console.log(` Tech preset: ${preview.selectedTechPreset}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return preview;
|
|
367
|
+
}
|
|
368
|
+
|
|
332
369
|
// Story 1.4: Install AIOX core framework (agents, tasks, workflows, templates)
|
|
333
370
|
console.log('\n📦 Installing AIOX core framework...');
|
|
334
371
|
let aioxCoreResult = null;
|
|
335
372
|
try {
|
|
336
373
|
aioxCoreResult = await installAioxCore({
|
|
337
374
|
targetDir: process.cwd(),
|
|
375
|
+
projectType: answers.projectType || 'greenfield',
|
|
338
376
|
onProgress: (_status) => {
|
|
339
377
|
// Silent progress - spinner handles feedback
|
|
340
378
|
},
|
|
@@ -522,6 +560,24 @@ async function runWizard(options = {}) {
|
|
|
522
560
|
answers.skillsCopied = 0;
|
|
523
561
|
}
|
|
524
562
|
|
|
563
|
+
// Local-first Codex flow: generate project-local /skills activators automatically
|
|
564
|
+
if ((answers.selectedIDEs || []).includes('codex')) {
|
|
565
|
+
console.log('\n🧠 Generating Codex skills...');
|
|
566
|
+
try {
|
|
567
|
+
const codexSkillsResult = generateCodexSkills(process.cwd());
|
|
568
|
+
if (codexSkillsResult.skipped) {
|
|
569
|
+
console.log(' ℹ️ Codex skills: canonical agent source not found (skipped)');
|
|
570
|
+
} else {
|
|
571
|
+
console.log(`✅ Codex skills: ${codexSkillsResult.count} generated`);
|
|
572
|
+
}
|
|
573
|
+
answers.codexSkillsGenerated = codexSkillsResult.count;
|
|
574
|
+
answers.codexSkillsSkipped = codexSkillsResult.skipped;
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.warn(`⚠️ Codex skills generation failed: ${error.message}`);
|
|
577
|
+
answers.codexSkillsGenerated = 0;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
525
581
|
// Story INS-4.3: Copy extra commands (Gap #12)
|
|
526
582
|
console.log('\n📋 Copying extra commands...');
|
|
527
583
|
try {
|
|
@@ -554,7 +610,7 @@ async function runWizard(options = {}) {
|
|
|
554
610
|
try {
|
|
555
611
|
await commandValidate({ quiet: true });
|
|
556
612
|
answers.ideSyncValidation = 'pass';
|
|
557
|
-
} catch (
|
|
613
|
+
} catch (_validateError) {
|
|
558
614
|
answers.ideSyncValidation = 'drift';
|
|
559
615
|
} finally {
|
|
560
616
|
console.log = _origLog;
|
|
@@ -570,6 +626,23 @@ async function runWizard(options = {}) {
|
|
|
570
626
|
process.chdir(savedCwd);
|
|
571
627
|
}
|
|
572
628
|
|
|
629
|
+
// ACORE-SKILLS.7: Generate Codex local skills in installed projects.
|
|
630
|
+
console.log('\n🧩 Running Codex skills sync...');
|
|
631
|
+
try {
|
|
632
|
+
const codexSkillsResult = syncCodexSkills({
|
|
633
|
+
sourceDir: path.join(targetProjectRoot, '.aiox-core', 'development', 'agents'),
|
|
634
|
+
localSkillsDir: path.join(targetProjectRoot, '.codex', 'skills'),
|
|
635
|
+
dryRun: false,
|
|
636
|
+
});
|
|
637
|
+
answers.codexSkillsStatus = 'synced';
|
|
638
|
+
answers.codexSkillsGenerated = codexSkillsResult.generated;
|
|
639
|
+
console.log(`✅ Codex skills: ${codexSkillsResult.generated} generated`);
|
|
640
|
+
} catch (codexSkillsError) {
|
|
641
|
+
console.warn(`⚠️ Codex skills sync failed: ${codexSkillsError.message} — run 'npm run sync:skills:codex' post-install`);
|
|
642
|
+
answers.codexSkillsStatus = 'failed';
|
|
643
|
+
answers.codexSkillsGenerated = 0;
|
|
644
|
+
}
|
|
645
|
+
|
|
573
646
|
// Story INS-4.6: Entity Registry Bootstrap — populate entity-registry.yaml on install
|
|
574
647
|
// Story INS-4.12: Fix module resolution + bootstrap timing
|
|
575
648
|
// Bootstrap runs AFTER .aiox-core deps are installed (aiox-core-installer.js:324-345)
|
|
@@ -722,38 +795,44 @@ async function runWizard(options = {}) {
|
|
|
722
795
|
console.error(` ${depsResult.errorMessage}`);
|
|
723
796
|
console.error(` Solution: ${depsResult.solution}`);
|
|
724
797
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
798
|
+
if (options.quiet || options.ci || process.env.CI === '1') {
|
|
799
|
+
answers.depsInstalled = false;
|
|
800
|
+
answers.depsResult = depsResult;
|
|
801
|
+
console.log('\n⚠️ Skipping dependency retry in non-interactive mode.');
|
|
802
|
+
} else {
|
|
803
|
+
// Ask user if they want to retry
|
|
804
|
+
const { retryDeps } = await inquirer.prompt([
|
|
805
|
+
{
|
|
806
|
+
type: 'confirm',
|
|
807
|
+
name: 'retryDeps',
|
|
808
|
+
message: 'Retry dependency installation?',
|
|
809
|
+
default: true,
|
|
810
|
+
},
|
|
811
|
+
]);
|
|
812
|
+
|
|
813
|
+
if (retryDeps) {
|
|
814
|
+
// Recursive retry with exponential backoff (built into installDependencies)
|
|
815
|
+
const retryResult = await installDependencies({
|
|
816
|
+
packageManager: answers.packageManager,
|
|
817
|
+
projectPath: projectPath,
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
if (retryResult.success) {
|
|
821
|
+
console.log(`\n✅ Dependencies installed with ${retryResult.packageManager}!`);
|
|
822
|
+
answers.depsInstalled = true;
|
|
823
|
+
answers.depsResult = retryResult;
|
|
824
|
+
} else {
|
|
825
|
+
console.log(
|
|
826
|
+
'\n⚠️ Installation still failed. You can run `npm install` manually later.',
|
|
827
|
+
);
|
|
828
|
+
answers.depsInstalled = false;
|
|
829
|
+
answers.depsResult = retryResult;
|
|
830
|
+
}
|
|
746
831
|
} else {
|
|
747
|
-
console.log(
|
|
748
|
-
'\n⚠️ Installation still failed. You can run `npm install` manually later.',
|
|
749
|
-
);
|
|
832
|
+
console.log('\n⚠️ Skipping dependency installation. Run manually with `npm install`.');
|
|
750
833
|
answers.depsInstalled = false;
|
|
751
|
-
answers.depsResult =
|
|
834
|
+
answers.depsResult = depsResult;
|
|
752
835
|
}
|
|
753
|
-
} else {
|
|
754
|
-
console.log('\n⚠️ Skipping dependency installation. Run manually with `npm install`.');
|
|
755
|
-
answers.depsInstalled = false;
|
|
756
|
-
answers.depsResult = depsResult;
|
|
757
836
|
}
|
|
758
837
|
}
|
|
759
838
|
} catch (error) {
|
|
@@ -910,6 +989,14 @@ async function runWizard(options = {}) {
|
|
|
910
989
|
console.log('\n🔍 Validating installation...\n');
|
|
911
990
|
|
|
912
991
|
try {
|
|
992
|
+
const expectedSkillDirs = [];
|
|
993
|
+
if ((answers.selectedIDEs || []).includes('claude-code')) {
|
|
994
|
+
expectedSkillDirs.push('.claude/skills');
|
|
995
|
+
}
|
|
996
|
+
if ((answers.selectedIDEs || []).includes('codex')) {
|
|
997
|
+
expectedSkillDirs.push(path.join('.codex', 'skills'));
|
|
998
|
+
}
|
|
999
|
+
|
|
913
1000
|
const validation = await validateInstallation(
|
|
914
1001
|
{
|
|
915
1002
|
files: {
|
|
@@ -917,6 +1004,7 @@ async function runWizard(options = {}) {
|
|
|
917
1004
|
env: '.env',
|
|
918
1005
|
coreConfig: '.aiox-core/core-config.yaml',
|
|
919
1006
|
mcpConfig: '.mcp.json',
|
|
1007
|
+
skillDirs: expectedSkillDirs,
|
|
920
1008
|
},
|
|
921
1009
|
configs: {
|
|
922
1010
|
env: answers.envResult,
|
|
@@ -39,7 +39,7 @@ const LICENSE_SERVER_URL = process.env.AIOX_LICENSE_API_URL || 'https://aiox-lic
|
|
|
39
39
|
/**
|
|
40
40
|
* Inline License Client — lightweight HTTP client for pre-bootstrap license checks.
|
|
41
41
|
*
|
|
42
|
-
* Used when @aiox-
|
|
42
|
+
* Used when @aiox-squads/pro is not yet installed (first install scenario).
|
|
43
43
|
* Implements the same interface subset as LicenseApiClient using Node.js native https.
|
|
44
44
|
*/
|
|
45
45
|
class InlineLicenseClient {
|
|
@@ -57,12 +57,12 @@ class InlineLicenseClient {
|
|
|
57
57
|
*/
|
|
58
58
|
_request(method, urlPath, body, headers = {}) {
|
|
59
59
|
return new Promise((resolve, reject) => {
|
|
60
|
-
const https = require('https');
|
|
61
60
|
const url = new URL(urlPath, this.baseUrl);
|
|
61
|
+
const transport = url.protocol === 'http:' ? require('http') : require('https');
|
|
62
62
|
|
|
63
63
|
const options = {
|
|
64
64
|
hostname: url.hostname,
|
|
65
|
-
port: url.port || 443,
|
|
65
|
+
port: url.port || (url.protocol === 'http:' ? 80 : 443),
|
|
66
66
|
path: url.pathname + url.search,
|
|
67
67
|
method,
|
|
68
68
|
headers: {
|
|
@@ -73,7 +73,7 @@ class InlineLicenseClient {
|
|
|
73
73
|
timeout: 15000,
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
const req =
|
|
76
|
+
const req = transport.request(options, (res) => {
|
|
77
77
|
let data = '';
|
|
78
78
|
res.on('data', (chunk) => { data += chunk; });
|
|
79
79
|
res.on('end', () => {
|
|
@@ -135,10 +135,19 @@ class InlineLicenseClient {
|
|
|
135
135
|
* Login with email and password.
|
|
136
136
|
* @param {string} email
|
|
137
137
|
* @param {string} password
|
|
138
|
-
* @returns {Promise<{sessionToken: string, emailVerified: boolean}>}
|
|
138
|
+
* @returns {Promise<{accessToken: string, sessionToken: string, emailVerified: boolean}>}
|
|
139
139
|
*/
|
|
140
140
|
async login(email, password) {
|
|
141
|
-
return this._request('POST', '/api/v1/auth/login', { email, password })
|
|
141
|
+
return this._request('POST', '/api/v1/auth/login', { email, password })
|
|
142
|
+
.then((result) => {
|
|
143
|
+
const accessToken = result.accessToken || result.sessionToken;
|
|
144
|
+
return {
|
|
145
|
+
...result,
|
|
146
|
+
accessToken,
|
|
147
|
+
// Backward-compatible alias for existing wizard flows.
|
|
148
|
+
sessionToken: accessToken,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
142
151
|
}
|
|
143
152
|
|
|
144
153
|
/**
|
|
@@ -160,11 +169,17 @@ class InlineLicenseClient {
|
|
|
160
169
|
*/
|
|
161
170
|
async activateByAuth(token, machineId, version) {
|
|
162
171
|
return this._request('POST', '/api/v1/auth/activate-pro', {
|
|
172
|
+
accessToken: token,
|
|
163
173
|
machineId,
|
|
164
174
|
version,
|
|
175
|
+
aioxCoreVersion: version,
|
|
165
176
|
}, {
|
|
177
|
+
// Preserve legacy compatibility with older server deployments.
|
|
166
178
|
Authorization: `Bearer ${token}`,
|
|
167
|
-
})
|
|
179
|
+
}).then((result) => ({
|
|
180
|
+
...result,
|
|
181
|
+
key: result.key || result.licenseKey,
|
|
182
|
+
}));
|
|
168
183
|
}
|
|
169
184
|
|
|
170
185
|
/**
|
|
@@ -175,8 +190,7 @@ class InlineLicenseClient {
|
|
|
175
190
|
* @returns {Promise<Object>} Activation result
|
|
176
191
|
*/
|
|
177
192
|
async activate(licenseKey, machineId, version) {
|
|
178
|
-
|
|
179
|
-
return this._request('POST', '/v1/license/activate', {
|
|
193
|
+
return this._request('POST', '/api/v1/licenses/activate', {
|
|
180
194
|
key: licenseKey,
|
|
181
195
|
machineId,
|
|
182
196
|
version,
|
|
@@ -185,13 +199,32 @@ class InlineLicenseClient {
|
|
|
185
199
|
|
|
186
200
|
/**
|
|
187
201
|
* Check if user's email has been verified.
|
|
188
|
-
* @param {string}
|
|
202
|
+
* @param {string} accessToken - Session token
|
|
189
203
|
* @returns {Promise<{verified: boolean}>}
|
|
190
204
|
*/
|
|
191
|
-
async checkEmailVerified(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
async checkEmailVerified(accessToken) {
|
|
206
|
+
try {
|
|
207
|
+
const result = await this._request('POST', '/api/v1/auth/verify-status', {
|
|
208
|
+
accessToken,
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
...result,
|
|
212
|
+
verified: result.verified ?? result.emailVerified,
|
|
213
|
+
};
|
|
214
|
+
} catch (error) {
|
|
215
|
+
// Older server versions used GET /email-verified with bearer auth.
|
|
216
|
+
if (!error.message || !error.message.includes('HTTP 404')) {
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const result = await this._request('GET', '/api/v1/auth/email-verified', null, {
|
|
221
|
+
Authorization: `Bearer ${accessToken}`,
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
...result,
|
|
225
|
+
verified: result.verified ?? result.emailVerified,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
195
228
|
}
|
|
196
229
|
|
|
197
230
|
/**
|
|
@@ -318,14 +351,14 @@ function showStep(current, total, label) {
|
|
|
318
351
|
*
|
|
319
352
|
* Resolution order:
|
|
320
353
|
* 1. Relative path (framework-dev mode: ../../../../pro/license/{name})
|
|
321
|
-
* 2. @aiox-
|
|
354
|
+
* 2. @aiox-squads/pro package (brownfield: node_modules/@aiox-squads/pro/license/{name})
|
|
322
355
|
* 3. Absolute path via aiox-core in node_modules (brownfield upgrade)
|
|
323
|
-
* 4. Absolute path via @aiox-
|
|
356
|
+
* 4. Absolute path via @aiox-squads/pro in user project (npx context)
|
|
324
357
|
*
|
|
325
358
|
* Path 4 is critical for npx execution: when running `npx aiox-core install`,
|
|
326
359
|
* require() resolves from the npx temp directory, not process.cwd(). After
|
|
327
|
-
* bootstrap installs @aiox-
|
|
328
|
-
* absolute path to process.cwd()/node_modules/@aiox-
|
|
360
|
+
* bootstrap installs @aiox-squads/pro in the user's project, only an
|
|
361
|
+
* absolute path to process.cwd()/node_modules/@aiox-squads/pro/... works.
|
|
329
362
|
*
|
|
330
363
|
* @param {string} moduleName - Module filename without extension (e.g., 'license-api')
|
|
331
364
|
* @returns {Object|null} Loaded module or null
|
|
@@ -354,8 +387,8 @@ function loadProModule(moduleName) {
|
|
|
354
387
|
return frameworkModule;
|
|
355
388
|
}
|
|
356
389
|
|
|
357
|
-
// 2. npm packages — try canonical then
|
|
358
|
-
const npmScopes = ['@aiox-fullstack/pro', '@aios-fullstack/pro'];
|
|
390
|
+
// 2. npm packages — try canonical then fallbacks
|
|
391
|
+
const npmScopes = ['@aiox-squads/pro', '@aiox-fullstack/pro', '@aios-fullstack/pro'];
|
|
359
392
|
for (const scope of npmScopes) {
|
|
360
393
|
const requestPath = `${scope}/license/${moduleName}`;
|
|
361
394
|
const loadedModule = tryRequire(requestPath);
|
|
@@ -373,7 +406,7 @@ function loadProModule(moduleName) {
|
|
|
373
406
|
|
|
374
407
|
// 4. npm package in user project via absolute path (npx context — require resolves from
|
|
375
408
|
// temp dir, so we need absolute path to where bootstrap installed the package)
|
|
376
|
-
const absScopeDirs = ['@aiox-fullstack', '@aios-fullstack'];
|
|
409
|
+
const absScopeDirs = ['@aiox-squads', '@aiox-fullstack', '@aios-fullstack'];
|
|
377
410
|
for (const scopeDir of absScopeDirs) {
|
|
378
411
|
const absPath = path.join(process.cwd(), 'node_modules', scopeDir, 'pro', 'license', moduleName);
|
|
379
412
|
const loadedModule = tryRequire(absPath);
|
|
@@ -459,7 +492,7 @@ function generateMachineId() {
|
|
|
459
492
|
/**
|
|
460
493
|
* Get a license API client instance.
|
|
461
494
|
*
|
|
462
|
-
* Prefers the full LicenseApiClient from @aiox-
|
|
495
|
+
* Prefers the full LicenseApiClient from @aiox-squads/pro when available.
|
|
463
496
|
* Falls back to InlineLicenseClient (native https) for pre-bootstrap scenarios.
|
|
464
497
|
*
|
|
465
498
|
* @returns {Object} Client instance with isOnline, checkEmail, login, signup, activateByAuth
|
|
@@ -475,7 +508,7 @@ function getLicenseClient() {
|
|
|
475
508
|
return new LicenseApiClient();
|
|
476
509
|
}
|
|
477
510
|
|
|
478
|
-
// Fallback: use inline client for pre-bootstrap (no @aiox-
|
|
511
|
+
// Fallback: use inline client for pre-bootstrap (no @aiox-squads/pro yet)
|
|
479
512
|
return new InlineLicenseClient();
|
|
480
513
|
}
|
|
481
514
|
|
|
@@ -584,6 +617,63 @@ async function ensureKeyValidationParity(client, activationResult, machineId, ai
|
|
|
584
617
|
}
|
|
585
618
|
}
|
|
586
619
|
|
|
620
|
+
/**
|
|
621
|
+
* Resolve the Pro content source directory.
|
|
622
|
+
*
|
|
623
|
+
* Priority:
|
|
624
|
+
* 1. Bundled pro/ content in the aiox-core checkout or package
|
|
625
|
+
* 2. Auto-initialize the git submodule when running from a source checkout
|
|
626
|
+
* 3. Installed @aiox-squads/pro package in the target project
|
|
627
|
+
*
|
|
628
|
+
* @param {string} targetDir - Project root directory
|
|
629
|
+
* @returns {{proSourceDir: string|null, bootstrapError?: string}} Resolution result
|
|
630
|
+
*/
|
|
631
|
+
function resolveProSourceDir(targetDir) {
|
|
632
|
+
const path = require('path');
|
|
633
|
+
const fs = require('fs');
|
|
634
|
+
const { execFileSync } = require('child_process');
|
|
635
|
+
|
|
636
|
+
const repoRoot = path.resolve(__dirname, '..', '..', '..', '..');
|
|
637
|
+
const bundledProDir = path.join(repoRoot, 'pro');
|
|
638
|
+
const npmProDirs = [
|
|
639
|
+
path.join(targetDir, 'node_modules', '@aiox-squads', 'pro'),
|
|
640
|
+
path.join(targetDir, 'node_modules', '@aiox-fullstack', 'pro'),
|
|
641
|
+
path.join(targetDir, 'node_modules', '@aios-fullstack', 'pro'),
|
|
642
|
+
];
|
|
643
|
+
const bundledSquadsDir = path.join(bundledProDir, 'squads');
|
|
644
|
+
const gitmodulesPath = path.join(repoRoot, '.gitmodules');
|
|
645
|
+
|
|
646
|
+
if (fs.existsSync(bundledSquadsDir)) {
|
|
647
|
+
return { proSourceDir: bundledProDir };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (fs.existsSync(gitmodulesPath) && fs.existsSync(bundledProDir)) {
|
|
651
|
+
try {
|
|
652
|
+
execFileSync('git', ['submodule', 'update', '--init', '--recursive', 'pro'], {
|
|
653
|
+
cwd: repoRoot,
|
|
654
|
+
stdio: 'ignore',
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
if (fs.existsSync(bundledSquadsDir)) {
|
|
658
|
+
return { proSourceDir: bundledProDir };
|
|
659
|
+
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
return {
|
|
662
|
+
proSourceDir: null,
|
|
663
|
+
bootstrapError: error.message || 'git submodule update failed',
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
for (const npmProDir of npmProDirs) {
|
|
669
|
+
if (fs.existsSync(npmProDir)) {
|
|
670
|
+
return { proSourceDir: npmProDir };
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return { proSourceDir: null };
|
|
675
|
+
}
|
|
676
|
+
|
|
587
677
|
/**
|
|
588
678
|
* Step 1: License Gate — authenticate and validate license.
|
|
589
679
|
*
|
|
@@ -728,7 +818,7 @@ async function stepLicenseGateWithEmail() {
|
|
|
728
818
|
let checkResult;
|
|
729
819
|
try {
|
|
730
820
|
checkResult = await client.checkEmail(trimmedEmail);
|
|
731
|
-
} catch (
|
|
821
|
+
} catch (_checkError) {
|
|
732
822
|
checkSpinner.info(t('proBuyerCheckUnavailable'));
|
|
733
823
|
return fallbackAuthWithoutBuyerCheck(client, trimmedEmail);
|
|
734
824
|
}
|
|
@@ -1431,32 +1521,12 @@ async function validateKeyWithApi(key) {
|
|
|
1431
1521
|
async function stepInstallScaffold(targetDir, options = {}) {
|
|
1432
1522
|
showStep(2, 3, t('proContentInstallation'));
|
|
1433
1523
|
|
|
1434
|
-
const
|
|
1435
|
-
const fs = require('fs');
|
|
1436
|
-
|
|
1437
|
-
// Resolve pro source directory from multiple locations:
|
|
1438
|
-
// 1. Bundled in aiox-core package (pro/ submodule — npx and local dev)
|
|
1439
|
-
// 2. npm package — canonical @aiox-fullstack/pro or fallback @aios-fullstack/pro
|
|
1440
|
-
const bundledProDir = path.resolve(__dirname, '..', '..', '..', '..', 'pro');
|
|
1441
|
-
const npmProCandidates = [
|
|
1442
|
-
path.join(targetDir, 'node_modules', '@aiox-fullstack', 'pro'),
|
|
1443
|
-
path.join(targetDir, 'node_modules', '@aios-fullstack', 'pro'),
|
|
1444
|
-
];
|
|
1445
|
-
|
|
1446
|
-
let proSourceDir;
|
|
1447
|
-
if (fs.existsSync(bundledProDir) && fs.existsSync(path.join(bundledProDir, 'squads'))) {
|
|
1448
|
-
proSourceDir = bundledProDir;
|
|
1449
|
-
} else {
|
|
1450
|
-
proSourceDir = npmProCandidates.find((candidate) => (
|
|
1451
|
-
fs.existsSync(path.join(candidate, 'package.json'))
|
|
1452
|
-
&& fs.existsSync(path.join(candidate, 'squads'))
|
|
1453
|
-
));
|
|
1454
|
-
}
|
|
1524
|
+
const { proSourceDir, bootstrapError } = resolveProSourceDir(targetDir);
|
|
1455
1525
|
|
|
1456
1526
|
if (!proSourceDir) {
|
|
1457
1527
|
return {
|
|
1458
1528
|
success: false,
|
|
1459
|
-
error: t('proPackageNotFound'),
|
|
1529
|
+
error: bootstrapError ? `${t('proPackageNotFound')} ${bootstrapError}` : t('proPackageNotFound'),
|
|
1460
1530
|
};
|
|
1461
1531
|
}
|
|
1462
1532
|
|
|
@@ -1610,7 +1680,7 @@ async function runProWizard(options = {}) {
|
|
|
1610
1680
|
showProHeader();
|
|
1611
1681
|
}
|
|
1612
1682
|
|
|
1613
|
-
// Step 1: License Gate (uses InlineLicenseClient if @aiox-
|
|
1683
|
+
// Step 1: License Gate (uses InlineLicenseClient if @aiox-squads/pro not yet installed)
|
|
1614
1684
|
const licenseResult = await stepLicenseGate({
|
|
1615
1685
|
key: options.key || process.env.AIOX_PRO_KEY,
|
|
1616
1686
|
email: options.email || process.env.AIOX_PRO_EMAIL,
|
|
@@ -1687,6 +1757,7 @@ module.exports = {
|
|
|
1687
1757
|
loadLicenseCache,
|
|
1688
1758
|
loadProScaffolder,
|
|
1689
1759
|
getLicenseClient,
|
|
1760
|
+
resolveProSourceDir,
|
|
1690
1761
|
InlineLicenseClient,
|
|
1691
1762
|
generateMachineId,
|
|
1692
1763
|
persistLicenseCache,
|
|
@@ -29,6 +29,7 @@ async function validateDependencies(depsContext = {}) {
|
|
|
29
29
|
errors: [],
|
|
30
30
|
warnings: [],
|
|
31
31
|
};
|
|
32
|
+
const projectRoot = depsContext.projectPath || depsContext.targetDir || process.cwd();
|
|
32
33
|
|
|
33
34
|
try {
|
|
34
35
|
// Check if dependencies were installed (skip for greenfield with no deps defined)
|
|
@@ -43,8 +44,8 @@ async function validateDependencies(depsContext = {}) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
// Check node_modules existence
|
|
46
|
-
const nodeModulesPath = path.join(
|
|
47
|
-
const packageJsonPath = path.join(
|
|
47
|
+
const nodeModulesPath = path.join(projectRoot, 'node_modules');
|
|
48
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
48
49
|
|
|
49
50
|
// For greenfield projects, check if package.json has dependencies
|
|
50
51
|
let hasDependencies = false;
|
|
@@ -92,13 +93,13 @@ async function validateDependencies(depsContext = {}) {
|
|
|
92
93
|
});
|
|
93
94
|
|
|
94
95
|
// Validate package.json integrity
|
|
95
|
-
await validatePackageJson(results);
|
|
96
|
+
await validatePackageJson(results, projectRoot);
|
|
96
97
|
|
|
97
|
-
//
|
|
98
|
-
await
|
|
98
|
+
// Validate any explicit dependency contract supplied by the caller.
|
|
99
|
+
await checkRequiredDependencies(results, projectRoot, depsContext.requiredDependencies);
|
|
99
100
|
|
|
100
101
|
// Run npm audit (non-blocking - warnings only)
|
|
101
|
-
await runSecurityAudit(results, depsContext.packageManager);
|
|
102
|
+
await runSecurityAudit(results, depsContext.packageManager, projectRoot);
|
|
102
103
|
|
|
103
104
|
// Count installed packages
|
|
104
105
|
await countInstalledPackages(results, nodeModulesPath);
|
|
@@ -121,8 +122,8 @@ async function validateDependencies(depsContext = {}) {
|
|
|
121
122
|
* Validate package.json
|
|
122
123
|
* @private
|
|
123
124
|
*/
|
|
124
|
-
async function validatePackageJson(results) {
|
|
125
|
-
const packageJsonPath = 'package.json';
|
|
125
|
+
async function validatePackageJson(results, projectRoot) {
|
|
126
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
126
127
|
|
|
127
128
|
if (!fs.existsSync(packageJsonPath)) {
|
|
128
129
|
results.errors.push({
|
|
@@ -165,22 +166,28 @@ async function validatePackageJson(results) {
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
168
|
-
* Check
|
|
169
|
+
* Check explicitly required dependencies for the target project.
|
|
170
|
+
*
|
|
171
|
+
* This validator is used against the installed project, not the installer
|
|
172
|
+
* workspace itself. A caller may provide a narrow manifest of packages that
|
|
173
|
+
* must exist after installation; when none is supplied we skip this check to
|
|
174
|
+
* avoid false warnings about the installer's own internal dependencies.
|
|
169
175
|
* @private
|
|
170
176
|
*/
|
|
171
|
-
async function
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
async function checkRequiredDependencies(results, projectRoot, requiredDependencies = []) {
|
|
178
|
+
if (!Array.isArray(requiredDependencies) || requiredDependencies.length === 0) {
|
|
179
|
+
results.checks.push({
|
|
180
|
+
component: 'Dependency Contract',
|
|
181
|
+
status: 'skipped',
|
|
182
|
+
message: 'No explicit required dependency manifest provided',
|
|
183
|
+
});
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const nodeModulesPath = path.join(projectRoot, 'node_modules');
|
|
181
188
|
const missingDeps = [];
|
|
182
189
|
|
|
183
|
-
for (const dep of
|
|
190
|
+
for (const dep of requiredDependencies) {
|
|
184
191
|
const depPath = path.join(nodeModulesPath, dep);
|
|
185
192
|
if (!fs.existsSync(depPath)) {
|
|
186
193
|
missingDeps.push(dep);
|
|
@@ -190,15 +197,15 @@ async function checkCriticalDependencies(results) {
|
|
|
190
197
|
if (missingDeps.length > 0) {
|
|
191
198
|
results.warnings.push({
|
|
192
199
|
severity: 'high',
|
|
193
|
-
message: `
|
|
200
|
+
message: `Required dependencies missing: ${missingDeps.join(', ')}`,
|
|
194
201
|
code: 'CRITICAL_DEPS_MISSING',
|
|
195
202
|
solution: 'Re-run dependency installation',
|
|
196
203
|
});
|
|
197
204
|
} else {
|
|
198
205
|
results.checks.push({
|
|
199
|
-
component: '
|
|
206
|
+
component: 'Dependency Contract',
|
|
200
207
|
status: 'success',
|
|
201
|
-
message: `All ${
|
|
208
|
+
message: `All ${requiredDependencies.length} required dependencies installed`,
|
|
202
209
|
});
|
|
203
210
|
}
|
|
204
211
|
}
|
|
@@ -207,13 +214,13 @@ async function checkCriticalDependencies(results) {
|
|
|
207
214
|
* Run security audit
|
|
208
215
|
* @private
|
|
209
216
|
*/
|
|
210
|
-
async function runSecurityAudit(results, packageManager = 'npm') {
|
|
217
|
+
async function runSecurityAudit(results, packageManager = 'npm', projectRoot = process.cwd()) {
|
|
211
218
|
try {
|
|
212
219
|
const auditCommand = packageManager === 'yarn' ? 'yarn audit --json' : 'npm audit --json';
|
|
213
220
|
|
|
214
221
|
const { stdout } = await execAsync(auditCommand, {
|
|
215
222
|
timeout: 10000,
|
|
216
|
-
cwd:
|
|
223
|
+
cwd: projectRoot,
|
|
217
224
|
});
|
|
218
225
|
|
|
219
226
|
let auditResults;
|
|
@@ -15,6 +15,7 @@ const fs = require('fs');
|
|
|
15
15
|
* @param {string} fileContext.env - .env file path
|
|
16
16
|
* @param {string} fileContext.coreConfig - core-config.yaml path
|
|
17
17
|
* @param {string} fileContext.mcpConfig - .mcp.json path
|
|
18
|
+
* @param {Array<string>} fileContext.skillDirs - Skill directories expected after install
|
|
18
19
|
* @returns {Promise<Object>} Validation result
|
|
19
20
|
*/
|
|
20
21
|
async function validateFiles(fileContext = {}) {
|
|
@@ -51,6 +52,31 @@ async function validateFiles(fileContext = {}) {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
if (fileContext.skillDirs && fileContext.skillDirs.length > 0) {
|
|
56
|
+
for (const skillDir of fileContext.skillDirs) {
|
|
57
|
+
const exists = fs.existsSync(skillDir);
|
|
58
|
+
const isDirectory = exists ? fs.statSync(skillDir).isDirectory() : false;
|
|
59
|
+
const check = {
|
|
60
|
+
component: 'Skills',
|
|
61
|
+
file: skillDir,
|
|
62
|
+
status: exists && isDirectory ? 'success' : 'failed',
|
|
63
|
+
message: exists && isDirectory ? 'Directory exists' : 'Directory missing',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
results.checks.push(check);
|
|
67
|
+
|
|
68
|
+
if (!exists || !isDirectory) {
|
|
69
|
+
results.success = false;
|
|
70
|
+
results.errors.push({
|
|
71
|
+
severity: 'high',
|
|
72
|
+
message: `Expected skill directory missing: ${skillDir}`,
|
|
73
|
+
file: skillDir,
|
|
74
|
+
code: 'SKILL_DIR_MISSING',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
54
80
|
// Validate .env file (Story 1.6)
|
|
55
81
|
const envPath = fileContext.env || '.env';
|
|
56
82
|
const envExists = fs.existsSync(envPath);
|