Skip to content
Open
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
3 changes: 2 additions & 1 deletion .aiox-core/cli/commands/metrics/cleanup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

const { Command } = require('commander');
const { MetricsCollector } = require('../../../quality/metrics-collector');
const { loadMetricsCollector } = require('./runtime');

/**
* Create the cleanup subcommand
Expand All @@ -26,6 +26,7 @@ function createCleanupCommand() {
.action(async (options) => {
try {
const retentionDays = parseInt(options.retention, 10);
const { MetricsCollector } = loadMetricsCollector();
const collector = new MetricsCollector({ retentionDays });
const metrics = await collector.getMetrics();

Expand Down
4 changes: 2 additions & 2 deletions .aiox-core/cli/commands/metrics/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

const { Command } = require('commander');
const { MetricsCollector } = require('../../../quality/metrics-collector');
const { loadMetricsCollector } = require('./runtime');

/**
* Create the record subcommand
Expand Down Expand Up @@ -39,8 +39,8 @@ function createRecordCommand() {
.option('-v, --verbose', 'Show detailed output', false)
.action(async (options) => {
try {
const { MetricsCollector } = loadMetricsCollector();
const collector = new MetricsCollector();

const layerNum = parseInt(options.layer, 10);
if (![1, 2, 3].includes(layerNum)) {
console.error('❌ Error: Layer must be 1, 2, or 3');
Expand Down
40 changes: 40 additions & 0 deletions .aiox-core/cli/commands/metrics/runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Metrics runtime loader helpers.
*
* Keeps metrics-only payload dependencies out of the general CLI boot path.
*/

function wrapMissingMetricsDependency(error) {
if (error?.code !== 'MODULE_NOT_FOUND') {
return error;
}

const wrapped = new Error(
'Metrics support is unavailable in this installation. ' +
'Reinstall or update the package so `.aiox-core/quality/` is included, ' +
'then retry the metrics command.',
);
wrapped.cause = error;
return wrapped;
}

function loadMetricsCollector() {
try {
return require('../../../quality/metrics-collector');
} catch (error) {
throw wrapMissingMetricsDependency(error);
}
}

function loadSeedMetricsModule() {
try {
return require('../../../quality/seed-metrics');
} catch (error) {
throw wrapMissingMetricsDependency(error);
}
}

module.exports = {
loadMetricsCollector,
loadSeedMetricsModule,
};
4 changes: 2 additions & 2 deletions .aiox-core/cli/commands/metrics/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

const { Command } = require('commander');
const { seedMetrics } = require('../../../quality/seed-metrics');
const { loadSeedMetricsModule } = require('./runtime');

/**
* Create the seed subcommand
Expand All @@ -27,6 +27,7 @@ function createSeedCommand() {
.option('-v, --verbose', 'Show detailed output', false)
.action(async (options) => {
try {
const { seedMetrics, generateSeedData } = loadSeedMetricsModule();
const seedOptions = {
days: parseInt(options.days, 10),
runsPerDay: parseInt(options.runs, 10),
Expand All @@ -41,7 +42,6 @@ function createSeedCommand() {

if (options.dryRun) {
// Generate but don't save
const { generateSeedData } = require('../../../quality/seed-metrics');
const metrics = generateSeedData(seedOptions);

console.log('\n📊 Generated Data Preview (dry run)');
Expand Down
3 changes: 2 additions & 1 deletion .aiox-core/cli/commands/metrics/show.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

const { Command } = require('commander');
const { MetricsCollector } = require('../../../quality/metrics-collector');
const { loadMetricsCollector } = require('./runtime');

/**
* Format percentage for display
Expand Down Expand Up @@ -67,6 +67,7 @@ function createShowCommand() {
.option('-v, --verbose', 'Show detailed output', false)
.action(async (options) => {
try {
const { MetricsCollector } = loadMetricsCollector();
const collector = new MetricsCollector();
const metrics = await collector.getMetrics();

Expand Down
83 changes: 83 additions & 0 deletions .aiox-core/core/errors/pro-error-registry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// PRO-UX.1 / PRO-UX.2 — Pro-specific error registry for the AIOX Pro CLI.
// Extends the canonical error-governance infra (EPIC-AIOX-ERROR-GOVERNANCE):
// reuses AIOXError + ErrorRegistry, maps to EXISTING ErrorCategory values
// (no new categories — constants.js is Object.freeze), and mirrors the
// license-server ErrorCodes (no AIOX_ prefix — deliberate, validated by the
// /^[A-Z0-9_]+$/ regex in ErrorRegistry._normalizeDefinition).
//
// userMessage holds the warm G3-approved PT-BR copy (fallback when the server
// envelope omits message_pt). recovery holds actionable PT-BR steps.

const { ErrorRegistry } = require('./error-registry');
const { ErrorCategory, ErrorSeverity } = require('./constants');

const PRO_ERROR_DEFINITIONS = Object.freeze([
{
code: 'SEAT_LIMIT_EXCEEDED',
category: ErrorCategory.PERMISSION, // license-server "auth says no" → permission
severity: ErrorSeverity.ERROR,
retryable: false,
exitCode: 13,
userMessage:
'Opa! Você já está usando o Pro no número máximo de máquinas. Pega o código de suporte aqui embaixo e fala com a gente que a gente libera rapidinho.',
recovery: [
'Pega o código de suporte abaixo',
'Cola no chat com o suporte',
'Depois que liberarem, roda o comando de instalação de novo',
],
},
{
code: 'NOT_A_BUYER',
category: ErrorCategory.PERMISSION,
severity: ErrorSeverity.ERROR,
retryable: false,
exitCode: 13,
userMessage:
'Hmm, sua licença Pro não está ativa no momento. Pega o código de suporte aqui embaixo e fala com a gente que resolvemos rapidinho.',
recovery: [
'Pega o código de suporte abaixo',
'Cola no chat com o suporte',
'Aguarda a verificação da sua compra',
],
},
{
code: 'REVOKED_KEY',
category: ErrorCategory.PERMISSION,
severity: ErrorSeverity.ERROR,
retryable: false,
exitCode: 13,
userMessage:
'Hmm, sua licença Pro não está ativa no momento. Pega o código de suporte aqui embaixo e fala com a gente que a gente verifica pra você.',
recovery: [
'Pega o código de suporte abaixo',
'Cola no chat com o suporte',
'Aguarda o retorno do financeiro',
],
},
{
code: 'RATE_LIMITED',
category: ErrorCategory.NETWORK, // throttling → network layer
severity: ErrorSeverity.WARNING,
retryable: true,
userMessage:
'Calma! Foram muitas tentativas em pouco tempo. Espera uns minutinhos e tenta de novo.',
recovery: ['Aguarda 5 minutos', 'Tenta o comando de novo'],
},
{
code: 'PRO_ARTIFACT_UNAVAILABLE',
category: ErrorCategory.EXTERNAL_EXECUTOR, // npm/tarball fetch → external executor
severity: ErrorSeverity.ERROR,
retryable: true,
userMessage:
'Tivemos um probleminha pra baixar o componente Pro. Limpa o cache e tenta de novo em alguns minutos que deve rolar.',
recovery: [
'Aguarda 5 minutos (o servidor pode estar reiniciando)',
'Roda `aiox install --recover-cache` para limpar o cache local',
'Tenta de novo',
],
},
]);

const proErrorRegistry = new ErrorRegistry(PRO_ERROR_DEFINITIONS);

module.exports = { proErrorRegistry, PRO_ERROR_DEFINITIONS };
Loading