Skip to content

Commit 0475f1d

Browse files
rafaelscostaclaude
andauthored
feat(errors): PRO-UX.1 + PRO-UX.2 — Pro CLI error UX bridge + root-cause fix (#775)
* feat(errors): pro-error-registry extending defaultErrorRegistry [Story PRO-UX.1] 5 top-5 codes mapped to EXISTING ErrorCategory (PERMISSION/NETWORK/ EXTERNAL_EXECUTOR — no invented categories). Warm G3 PT-BR userMessage + recovery arrays. Codes mirror license-server (no AIOX_ prefix). No collision with core registry. 7 tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(pro-cli): envelope bridge + warm render + OS-aware recovery [Story PRO-UX.1][Story PRO-UX.2] - error-bridge: parseEnvelopeToAIOXError, 3-tier fallback (message_pt > registry.userMessage > server message), graceful on legacy/malformed - render-error: warm output + numbered steps + support_code + conditional support link + technical footer - recovery-actions: planRecoveryAction + OS-aware cache cleanup (PowerShell vs bash — fixes the bug that made Robert run bash in PowerShell) - 15 tests (bridge fallback, render anchor case, cross-platform) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(installer): parse nested error envelope in pro-setup _request [Story PRO-UX.1] ROOT CAUSE of the anchor incident (Robert's opaque "HTTP 403"): _request read parsed.message / parsed.code at the ROOT, but the structured envelope nests them under `error`. So err.code was always undefined → the typed error branches (NOT_A_BUYER, SEAT_LIMIT_EXCEEDED, ...) in runProWizard were NEVER reached → fell through to the generic "HTTP <status>" message. Fix: read errorBody from parsed.error (nested) first, attach err.httpStatus + err.envelope for downstream renderError. Restores the existing i18n error branches. Preserves legacy root-shape compat. pro-setup suite 39/39 green (no regression). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(ids): register pro-error-registry in entity registry [Story PRO-UX.1] IDS hook auto-registration for .aiox-core/core/errors/pro-error-registry.js. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(ids): regen entity-registry deterministically [Story PRO-UX.1] The IDS hook's incremental update diverged from clean regen output (structural delta). Regenerated via populate-entity-registry.js. validate:registry-determinism now PASSES (821 entities). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(pro-cli): null/non-object guards in renderError + pro-setup fallback [Story PRO-UX.2] Addresses 2 CodeRabbit Major findings on PR #775: - renderError: guard against null/non-object err (prints generic message) - pro-setup _request: guard parsed.message/parsed.code against parsed === null The 5 "absolute import" suggestions are NOT applied: CLI runtime modules (error-bridge, pro-error-registry) require relative paths — there is no runtime module alias for `aiox-core/*` outside Jest's moduleNameMapper. Same-dir `./` imports do not violate the no-`../../../` rule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e9d088c commit 0475f1d

11 files changed

Lines changed: 1329 additions & 830 deletions

File tree

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// PRO-UX.1 / PRO-UX.2 — Pro-specific error registry for the AIOX Pro CLI.
2+
// Extends the canonical error-governance infra (EPIC-AIOX-ERROR-GOVERNANCE):
3+
// reuses AIOXError + ErrorRegistry, maps to EXISTING ErrorCategory values
4+
// (no new categories — constants.js is Object.freeze), and mirrors the
5+
// license-server ErrorCodes (no AIOX_ prefix — deliberate, validated by the
6+
// /^[A-Z0-9_]+$/ regex in ErrorRegistry._normalizeDefinition).
7+
//
8+
// userMessage holds the warm G3-approved PT-BR copy (fallback when the server
9+
// envelope omits message_pt). recovery holds actionable PT-BR steps.
10+
11+
const { ErrorRegistry } = require('./error-registry');
12+
const { ErrorCategory, ErrorSeverity } = require('./constants');
13+
14+
const PRO_ERROR_DEFINITIONS = Object.freeze([
15+
{
16+
code: 'SEAT_LIMIT_EXCEEDED',
17+
category: ErrorCategory.PERMISSION, // license-server "auth says no" → permission
18+
severity: ErrorSeverity.ERROR,
19+
retryable: false,
20+
exitCode: 13,
21+
userMessage:
22+
'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.',
23+
recovery: [
24+
'Pega o código de suporte abaixo',
25+
'Cola no chat com o suporte',
26+
'Depois que liberarem, roda o comando de instalação de novo',
27+
],
28+
},
29+
{
30+
code: 'NOT_A_BUYER',
31+
category: ErrorCategory.PERMISSION,
32+
severity: ErrorSeverity.ERROR,
33+
retryable: false,
34+
exitCode: 13,
35+
userMessage:
36+
'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.',
37+
recovery: [
38+
'Pega o código de suporte abaixo',
39+
'Cola no chat com o suporte',
40+
'Aguarda a verificação da sua compra',
41+
],
42+
},
43+
{
44+
code: 'REVOKED_KEY',
45+
category: ErrorCategory.PERMISSION,
46+
severity: ErrorSeverity.ERROR,
47+
retryable: false,
48+
exitCode: 13,
49+
userMessage:
50+
'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ê.',
51+
recovery: [
52+
'Pega o código de suporte abaixo',
53+
'Cola no chat com o suporte',
54+
'Aguarda o retorno do financeiro',
55+
],
56+
},
57+
{
58+
code: 'RATE_LIMITED',
59+
category: ErrorCategory.NETWORK, // throttling → network layer
60+
severity: ErrorSeverity.WARNING,
61+
retryable: true,
62+
userMessage:
63+
'Calma! Foram muitas tentativas em pouco tempo. Espera uns minutinhos e tenta de novo.',
64+
recovery: ['Aguarda 5 minutos', 'Tenta o comando de novo'],
65+
},
66+
{
67+
code: 'PRO_ARTIFACT_UNAVAILABLE',
68+
category: ErrorCategory.EXTERNAL_EXECUTOR, // npm/tarball fetch → external executor
69+
severity: ErrorSeverity.ERROR,
70+
retryable: true,
71+
userMessage:
72+
'Tivemos um probleminha pra baixar o componente Pro. Limpa o cache e tenta de novo em alguns minutos que deve rolar.',
73+
recovery: [
74+
'Aguarda 5 minutos (o servidor pode estar reiniciando)',
75+
'Roda `aiox install --recover-cache` para limpar o cache local',
76+
'Tenta de novo',
77+
],
78+
},
79+
]);
80+
81+
const proErrorRegistry = new ErrorRegistry(PRO_ERROR_DEFINITIONS);
82+
83+
module.exports = { proErrorRegistry, PRO_ERROR_DEFINITIONS };

0 commit comments

Comments
 (0)