@softize/opus 12.10.0 → 13.0.0

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/bin/lib/check.mjs +1098 -310
  3. package/bin/lib/copy.mjs +12 -5
  4. package/docs/adr/0003-dictionary-presentation-is-declared.md +3 -0
  5. package/docs/adr/0004-page-content-state-is-composed.md +65 -0
  6. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +180 -0
  7. package/docs/adr/0006-semantic-context-precedes-visual-variant.md +182 -0
  8. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  9. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  10. package/docs/radius-scale.md +1 -1
  11. package/package.json +1 -1
  12. package/registry/instructions/opus.md +5 -0
  13. package/registry/skills/build-opus-ui/SKILL.md +27 -16
  14. package/registry/skills/build-opus-ui/references/evaluations.md +16 -5
  15. package/registry/skills/build-opus-ui/references/ui-patterns.md +38 -15
  16. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  17. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  18. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  19. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  20. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  21. package/registry/skills/model-opus-dictionary/SKILL.md +4 -2
  22. package/registry/skills/model-opus-dictionary/references/evaluations.md +4 -3
  23. package/registry/templates/app/src/App.tsx +1 -1
  24. package/src/core/dictionary.ts +52 -14
  25. package/src/core/index.ts +10 -0
  26. package/src/core/ui-context.ts +29 -0
  27. package/src/schema/drivers/zod.ts +17 -8
  28. package/src/ui/components/patterns/action-form-card.tsx +18 -12
  29. package/src/ui/components/patterns/confirm.tsx +163 -40
  30. package/src/ui/components/patterns/content-header.tsx +335 -61
  31. package/src/ui/components/patterns/data-state.tsx +23 -10
  32. package/src/ui/components/patterns/list.tsx +1097 -783
  33. package/src/ui/components/patterns/page-state.tsx +115 -0
  34. package/src/ui/components/patterns/page.tsx +231 -41
  35. package/src/ui/components/patterns/sidebar.tsx +357 -83
  36. package/src/ui/components/patterns/trigger.tsx +37 -30
  37. package/src/ui/components/patterns/view.tsx +7 -11
  38. package/src/ui/components/primitives/alert.tsx +298 -110
  39. package/src/ui/components/primitives/ask.tsx +2 -1
  40. package/src/ui/components/primitives/badge.tsx +91 -30
  41. package/src/ui/components/primitives/button.tsx +99 -60
  42. package/src/ui/components/primitives/calendar.tsx +39 -39
  43. package/src/ui/components/primitives/card.tsx +96 -23
  44. package/src/ui/components/primitives/detail.tsx +2 -2
  45. package/src/ui/components/primitives/dialog.tsx +196 -39
  46. package/src/ui/components/primitives/dictionary-value.tsx +9 -14
  47. package/src/ui/components/primitives/dot.tsx +74 -21
  48. package/src/ui/components/primitives/drawer.tsx +40 -24
  49. package/src/ui/components/primitives/empty.tsx +3 -3
  50. package/src/ui/components/primitives/item.tsx +135 -79
  51. package/src/ui/components/primitives/menu.tsx +11 -3
  52. package/src/ui/components/primitives/metric-card.tsx +133 -0
  53. package/src/ui/components/primitives/sonner.tsx +187 -8
  54. package/src/ui/components/primitives/table.tsx +2 -2
  55. package/src/ui/docs/DocBrowser.tsx +104 -25
  56. package/src/ui/docs/changelog.tsx +1 -1
  57. package/src/ui/docs/content/accordion.md +22 -16
  58. package/src/ui/docs/content/action-form-card.md +8 -8
  59. package/src/ui/docs/content/action-form-dialog.md +9 -9
  60. package/src/ui/docs/content/action-form.md +28 -34
  61. package/src/ui/docs/content/action-list-dialog.md +11 -6
  62. package/src/ui/docs/content/action-list.md +64 -39
  63. package/src/ui/docs/content/action-trigger.md +21 -14
  64. package/src/ui/docs/content/action-view.md +8 -8
  65. package/src/ui/docs/content/actions.md +9 -9
  66. package/src/ui/docs/content/ai.md +3 -3
  67. package/src/ui/docs/content/alert.md +54 -28
  68. package/src/ui/docs/content/aspect-ratio.md +4 -4
  69. package/src/ui/docs/content/audit.md +2 -2
  70. package/src/ui/docs/content/auth.md +3 -3
  71. package/src/ui/docs/content/avatar.md +34 -14
  72. package/src/ui/docs/content/badge.md +21 -22
  73. package/src/ui/docs/content/breadcrumb.md +13 -8
  74. package/src/ui/docs/content/button.md +93 -15
  75. package/src/ui/docs/content/calendar.md +5 -5
  76. package/src/ui/docs/content/card.md +6 -6
  77. package/src/ui/docs/content/carousel.md +16 -11
  78. package/src/ui/docs/content/chat.md +3 -3
  79. package/src/ui/docs/content/checkbox.md +7 -7
  80. package/src/ui/docs/content/cli.md +5 -5
  81. package/src/ui/docs/content/collapsible.md +8 -8
  82. package/src/ui/docs/content/command.md +16 -8
  83. package/src/ui/docs/content/composer.md +2 -2
  84. package/src/ui/docs/content/content.md +44 -0
  85. package/src/ui/docs/content/copyable.md +4 -3
  86. package/src/ui/docs/content/customization.md +7 -7
  87. package/src/ui/docs/content/cycle.md +3 -3
  88. package/src/ui/docs/content/data-state.md +11 -12
  89. package/src/ui/docs/content/data.md +26 -33
  90. package/src/ui/docs/content/detail.md +8 -5
  91. package/src/ui/docs/content/dialog.md +339 -31
  92. package/src/ui/docs/content/dictionary-value.md +19 -18
  93. package/src/ui/docs/content/dock.md +3 -3
  94. package/src/ui/docs/content/dot.md +7 -7
  95. package/src/ui/docs/content/drawer.md +32 -16
  96. package/src/ui/docs/content/empty-value.md +2 -2
  97. package/src/ui/docs/content/empty.md +19 -12
  98. package/src/ui/docs/content/events.md +4 -4
  99. package/src/ui/docs/content/field.md +34 -12
  100. package/src/ui/docs/content/getting-started.md +1 -1
  101. package/src/ui/docs/content/icon-picker.md +8 -4
  102. package/src/ui/docs/content/input-otp.md +20 -12
  103. package/src/ui/docs/content/input.md +121 -9
  104. package/src/ui/docs/content/item.md +64 -24
  105. package/src/ui/docs/content/kbd.md +19 -11
  106. package/src/ui/docs/content/label.md +5 -3
  107. package/src/ui/docs/content/log.md +4 -4
  108. package/src/ui/docs/content/markdown.md +7 -6
  109. package/src/ui/docs/content/mcp.md +13 -15
  110. package/src/ui/docs/content/menu.md +36 -17
  111. package/src/ui/docs/content/metric-card.md +41 -0
  112. package/src/ui/docs/content/observability.md +2 -2
  113. package/src/ui/docs/content/page.md +93 -10
  114. package/src/ui/docs/content/pagination.md +22 -17
  115. package/src/ui/docs/content/popover.md +16 -8
  116. package/src/ui/docs/content/progress.md +7 -5
  117. package/src/ui/docs/content/queue.md +5 -5
  118. package/src/ui/docs/content/radio-group.md +20 -12
  119. package/src/ui/docs/content/router.md +11 -6
  120. package/src/ui/docs/content/scheduler.md +4 -5
  121. package/src/ui/docs/content/scroll-area.md +12 -7
  122. package/src/ui/docs/content/select.md +42 -29
  123. package/src/ui/docs/content/semantic-context.md +63 -0
  124. package/src/ui/docs/content/separator.md +5 -5
  125. package/src/ui/docs/content/sidebar.md +325 -56
  126. package/src/ui/docs/content/skeleton.md +5 -4
  127. package/src/ui/docs/content/slider.md +8 -7
  128. package/src/ui/docs/content/spinner.md +8 -8
  129. package/src/ui/docs/content/split.md +8 -5
  130. package/src/ui/docs/content/storage.md +6 -8
  131. package/src/ui/docs/content/switch.md +8 -7
  132. package/src/ui/docs/content/table.md +16 -6
  133. package/src/ui/docs/content/tabs.md +28 -14
  134. package/src/ui/docs/content/testing.md +9 -11
  135. package/src/ui/docs/content/textarea.md +5 -4
  136. package/src/ui/docs/content/toast.md +47 -13
  137. package/src/ui/docs/content/toggle.md +75 -7
  138. package/src/ui/docs/content/tokens.md +31 -3
  139. package/src/ui/docs/content/tooltip.md +19 -11
  140. package/src/ui/docs/content/truncate.md +7 -8
  141. package/src/ui/docs/content/ui.md +10 -9
  142. package/src/ui/docs/content/upgrading.md +7 -8
  143. package/src/ui/docs/doc-client.tsx +2 -2
  144. package/src/ui/docs/registry.tsx +580 -229
  145. package/src/ui/lib/semantic-context.ts +30 -0
  146. package/src/ui/meta.ts +278 -286
  147. package/src/ui/react.tsx +377 -111
  148. package/src/ui/theme.css +116 -0
  149. package/src/ui/components/primitives/alert-dialog.tsx +0 -190
  150. package/src/ui/docs/content/alert-dialog.md +0 -73
  151. package/src/ui/docs/content/button-group.md +0 -71
  152. package/src/ui/docs/content/confirm.md +0 -120
  153. package/src/ui/docs/content/input-group.md +0 -78
  154. package/src/ui/docs/content/toggle-group.md +0 -81
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softize/opus",
3
- "version": "12.10.0",
3
+ "version": "13.0.0",
4
4
  "description": "End-to-end action protocol for TypeScript. Single package with subpath exports (core + adapters).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -15,6 +15,11 @@ artefatos de agentes fica em `base.json`; cada app Opus mantém seu marcador `op
15
15
  - Manter contrato compartilhável separado de banco, segredo e driver server-only; usar
16
16
  `defineContract` com `bindAction` quando cliente e servidor consomem a mesma action.
17
17
  - Não duplicar schemas, tipos de transporte, validação ou fetch que o contrato já fornece.
18
+ - Em UI semântica, declarar primeiro `context` (`neutral`, `primary`, `info`, `success`, `warning`
19
+ ou `danger`) e usar `variant` somente para o tratamento visual (`solid`, `subtle`, `outline`,
20
+ `ghost` ou `link`). Dicionários de status e estágio declaram `context`; `tone` e variantes
21
+ semânticas antigas são apenas compatibilidade de migração. `destructive` permanece uma
22
+ propriedade comportamental de actions e se projeta visualmente como `danger`.
18
23
  - Declarar datasets persistentes com `defineSeed` + `bindSeed`, registrá-los em `opus.config.ts`
19
24
  e operá-los por `opus seed`; não criar comandos de seed paralelos nem reset implícito.
20
25
  - Regenerar o inventário com `opus copy` quando mudar copy em contrato ou componente Opus
@@ -19,46 +19,54 @@ existentes, mantendo navegação observável e componentes reutilizáveis sem la
19
19
  mensagem de vocabulário fechado vêm do dicionário do domínio (`labelFor`/`metaFor`); ao
20
20
  encontrar catálogo repetido à mão ou vocabulário ainda sem dicionário, carregar
21
21
  `$model-opus-dictionary`.
22
- 3. Apresentar valor de dicionário por `DictionaryValue` ou pela coluna de `ActionList`, que
22
+ 3. Em componentes semânticos, declarar `context` antes de escolher `variant`: `context` comunica
23
+ `neutral`, `primary`, `info`, `success`, `warning` ou `danger`; `variant` descreve somente o
24
+ tratamento `solid`, `subtle`, `outline`, `ghost` ou `link`, conforme o subconjunto aceito pelo
25
+ componente. Não usar `variant="success"`, `variant="destructive"` nem `tone` em código novo.
26
+ `destructive` permanece metadata comportamental de action e se projeta como `context="danger"`.
27
+ 4. Apresentar valor de dicionário por `DictionaryValue` ou pela coluna de `ActionList`, que
23
28
  aplicam o papel declarado em `presentation` (classificação em badge `outline`, status e estágio
24
- em badge tonal, `plain` em texto). Não escolher badge, tom ou ícone pelo nome do dicionário:
29
+ em badge `context + subtle`, `plain` em texto). Não escolher badge, contexto ou ícone pelo nome do dicionário:
25
30
  dicionário sem papel declarado renderiza texto e pede classificação por
26
31
  `$model-opus-dictionary` antes de qualquer destaque visual. Sobrepor os defaults só com motivo
27
32
  explícito nas props do renderer.
28
- 4. Dar a cada dimensão independente usada para comparação ou filtro um campo, coluna ou espaço
33
+ 5. Dar a cada dimensão independente usada para comparação ou filtro um campo, coluna ou espaço
29
34
  identificável próprio, com rótulo. Hierarquia tipográfica (texto secundário sob um nome) não
30
35
  pode fazer uma dimensão parecer explicação de outra. Cor e ícone reforçam; o texto do valor
31
36
  permanece sempre presente.
32
- 5. Deixar ausência, paginação e largura de filtro com o pattern: célula e `DetailField` já
37
+ 6. Deixar ausência, paginação e largura de filtro com o pattern: célula e `DetailField` já
33
38
  representam valor ausente (`EmptyValue`, `empty` para o significado do domínio); listas
34
39
  paginam pela primitiva `Pagination`; selects inline de filtro têm largura fixa. Não reescrever
35
40
  esses defaults na tela.
36
- 6. Tratar página, filtro, seleção e modal importante como estado navegável por URL quando
41
+ 7. Tratar página, filtro, seleção e modal importante como estado navegável por URL quando
37
42
  o produto precisa de deep link, back/forward ou refresh.
38
- 7. Compor páginas com `Page` e seu teto centralizado padrão de `72rem`. Usar
39
- `ContentHeader` em seções que precisam da mesma estrutura de título, descrição,
40
- metadados e ações; ajustar `level` pela hierarquia semântica, não pelo destaque visual.
41
- 8. Manter margem e posicionamento no consumidor; componente reutilizável controla apenas
43
+ 8. Compor superfícies pela gramática estrutural do catálogo: `Page` contém `PageHeader` e
44
+ `PageBody`; `Content` contém `ContentHeader` e `ContentBody`; Card, Drawer e Pane usam seus
45
+ respectivos `*Body`. Para o caso direto, usar a sintaxe abreviada de `Page` ou `Content` com
46
+ `title`, `description`, `meta` e `actions`; não misturá-la com o header explícito. Ajustar o
47
+ nível do heading pela hierarquia semântica, não pelo destaque visual. O `Page` mantém seu teto
48
+ centralizado padrão de `80rem`.
49
+ 9. Manter margem e posicionamento no consumidor; componente reutilizável controla apenas
42
50
  seu interior.
43
- 9. Não definir a fonte raiz em uma biblioteca ou componente. O navegador e a aplicação são
51
+ 10. Não definir a fonte raiz em uma biblioteca ou componente. O navegador e a aplicação são
44
52
  responsáveis por `font-size` em `html`; medidas escaláveis da UI usam `rem` ou a escala
45
53
  relativa do Tailwind. Reservar `px` a hairlines e compensações presas à geometria da borda,
46
54
  com justificativa e cobertura explícitas.
47
- 10. Evoluir um pattern compartilhado apenas quando a recorrência e o contrato estiverem claros.
48
- 11. Tratar tokens de superfície como pares indivisíveis no mesmo fragmento de classes:
55
+ 11. Evoluir um pattern compartilhado apenas quando a recorrência e o contrato estiverem claros.
56
+ 12. Tratar tokens de superfície como pares indivisíveis no mesmo fragmento de classes:
49
57
  `bg-card text-card-foreground` e `bg-popover text-popover-foreground`. Não depender da
50
58
  igualdade atual com `--foreground`, porque o app pode sobrescrever cada par.
51
- 12. Usar diretamente a escala `rounded-*`; não criar radius por nome de componente quando
59
+ 13. Usar diretamente a escala `rounded-*`; não criar radius por nome de componente quando
52
60
  `rounded-xs` a `rounded-2xl` já expressam a forma. Escolher o degrau pela escala visual:
53
61
  detalhes e itens internos tendem a `xs`/`sm`, controles e flutuantes compactos a `md`,
54
62
  molduras estruturais a `lg`, e superfícies principais ou modais a `xl`. Essa associação
55
63
  orienta o default, não cria uma restrição semântica. Em aninhamento, evitar moldura dupla e
56
64
  reduzir o raio interno; em grupos conectados, remover os raios das arestas internas. Tamanho
57
65
  e forma permanecem eixos separados; usar `shape="pill"` quando a pílula for intencional.
58
- 13. Distinguir uma região disponível para criação ou vínculo, representada por `Empty` com
66
+ 14. Distinguir uma região disponível para criação ou vínculo, representada por `Empty` com
59
67
  moldura tracejada, de um resultado vazio dentro de uma estrutura existente, que preserva
60
68
  a moldura sólida dessa estrutura.
61
- 14. Testar estados de loading, vazio, erro, sucesso, permissão e interação relevante.
69
+ 15. Testar estados de loading, vazio, erro, sucesso, permissão e interação relevante.
62
70
 
63
71
  ## Verificação
64
72
 
@@ -76,8 +84,11 @@ Inspecionar visualmente a rota real e validar navegação por URL quando aplicá
76
84
  - Não criar fetch, schema ou tipo paralelo ao contrato.
77
85
  - Não copiar componente da lib para customizar sem antes verificar extensão/composição.
78
86
  - Não forçar modal roteável quando o estado é efêmero e sem valor de navegação.
79
- - Não inferir apresentação de dicionário: nem badge para todo valor, nem tom ou ícone
87
+ - Não inferir apresentação de dicionário: nem badge para todo valor, nem contexto ou ícone
80
88
  inventados, nem tooltip que repete o rótulo.
89
+ - Não usar nomes de compatibilidade (`tone`, `variant="success"`, `variant="destructive"`) em
90
+ código novo; consultar a página “Contexto & Variante” do catálogo quando a combinação não estiver
91
+ clara.
81
92
  - Não repetir fallback de ausência, paginador ou largura de filtro que o pattern já resolve.
82
93
 
83
94
  ## Recursos
@@ -3,11 +3,14 @@
3
3
  - Dispara: “Monte a tela de edição usando a form action do Opus.”
4
4
  - Não dispara: “Ajuste o CSS de um e-mail estático.”
5
5
  - Execução: implementar uma lista com modal roteável e provar loading, erro, vazio e back.
6
- - Execução estrutural: montar uma página de relatório com `Page`, `ContentHeader` em uma seção,
7
- `ActionFilterBar` separado do renderer, `ItemGroup` para uma coleção secundária e um
8
- `ActionFormDialog`; provar teto padrão de `72rem`, hierarquia por `level`, vazio estrutural
9
- sólido, `Empty` apenas para criação ou vínculo, números sem alinhamento inferido e cancelamento
10
- `ghost` no modal.
6
+ - Execução estrutural: montar uma página de relatório com `Page > PageHeader + PageBody`, uma seção
7
+ `Content > ContentHeader + ContentBody`, `ActionFilterBar` separado do renderer, `ItemGroup` para
8
+ uma coleção secundária e um `ActionFormDialog`; provar teto padrão de `80rem`, hierarquia por
9
+ `level`, vazio estrutural sólido, `Empty` apenas para criação ou vínculo, números sem alinhamento
10
+ inferido e cancelamento `ghost` no modal.
11
+ - Execução abreviada: montar outra página com `<Page title description actions>` e uma seção com
12
+ `<Content title description actions>`, provando que ambas produzem a mesma anatomia e que o lint
13
+ rejeita a mistura entre props abreviadas e headers explícitos.
11
14
  - Execução de forma: compor uma tabela dentro de Card sem moldura duplicada, manter a moldura
12
15
  estrutural standalone em `rounded-lg` e os controles internos em `rounded-md`.
13
16
  - Reprova: criar uma casca `bg-card` que herda o texto global ou introduzir `rounded-widget`
@@ -17,11 +20,19 @@
17
20
  - Reprova: reconstruir manualmente o container de página, usar `Empty` tracejado como vazio de
18
21
  tabela, alinhar toda coluna numérica à direita por inferência ou destacar “Cancelar” como ação
19
22
  primária em modal.
23
+ - Reprova: deixar `ContentHeader` fora de `Content`, omitir `PageBody`/`ContentBody` na composição
24
+ explícita, usar `CardContent`/`PaneContent` em código novo ou tratar `DialogContent` como Body.
20
25
  - Execução de dicionários: montar a lista de clientes com “Pessoa física/Empresa” e
21
26
  “Prospect/Cliente”; provar que o tipo ocupa a coluna “Tipo” como classificação (badge `outline`
22
27
  com os ícones declarados `user` e `building`), que o estágio ocupa a coluna “Estágio” como badge
23
28
  tonal sem `outline`, que nenhuma das duas usa `cells`, que o texto do valor está presente e que
24
29
  não há tooltip em “Pessoa física/Empresa” quando a descrição não acrescenta ao rótulo.
30
+ - Execução de contexto: montar ações, badges, alertas e indicadores com o mesmo estado `warning`;
31
+ exigir `context="warning"`, variantes visuais coerentes por componente e tokens da mesma família.
32
+ Uma exclusão continua `destructive` no contrato, mas usa `context="danger"` na projeção visual.
33
+ - Reprova: usar `tone` em componente novo, `variant="success"`, `variant="warning"` ou
34
+ `variant="destructive"`; usar `light`/`dark` como contexto; ou tratar `secondary` como sinônimo
35
+ de estado neutro.
25
36
  - Reprova: envolver todo valor de dicionário em badge sem papel declarado, ou escolher a variante
26
37
  pelo nome do dicionário.
27
38
  - Reprova: colocar duas dimensões independentes na mesma célula sem identificação, como o tipo em
@@ -4,12 +4,24 @@
4
4
  - Campos, labels, mensagens e invalidações pertencem ao contrato quando são parte da
5
5
  operação, não a uma tela isolada.
6
6
  - URL representa estado que precisa sobreviver a refresh, deep link ou histórico.
7
- - `Page` fornece o `<main>`, o container centralizado com teto padrão de `72rem` e o header
8
- de página. Alterar `className` apenas quando a superfície tiver uma necessidade real de
9
- largura; não reconstruir esse container em cada rota.
10
- - `ContentHeader` compartilha a composição de título, descrição, metadados e ações entre
11
- páginas e seções. `variant` define o destaque visual; `level` preserva separadamente a
12
- hierarquia semântica do heading.
7
+ - `Page` fornece o `<main>` e o container centralizado com teto padrão de `80rem`. Sua forma
8
+ explícita é `Page > PageHeader (PageTitle, PageDescription, PageMeta, PageActions) + PageBody`;
9
+ `title`, `description`, `meta` e `actions` no próprio `Page` são a abreviação para o caso direto.
10
+ Não misturar as duas formas. Alterar `className` apenas quando a superfície tiver uma necessidade
11
+ real de largura; não reconstruir esse container em cada rota.
12
+ - `PageState` substitui todo o conteúdo principal quando a página carrega, falha ou está vazia. Na
13
+ forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
14
+ explícita, fica dentro de `PageBody`. O cabeçalho permanece visível. Estados de seção ou coleção
15
+ continuam em `DataState`, `ActionView`, `ActionList` ou `Alert`; não elevar uma falha parcial a
16
+ estado da página.
17
+ - `Content` delimita uma seção e segue a mesma anatomia: `Content > ContentHeader (ContentTitle,
18
+ ContentDescription, ContentMeta, ContentActions) + ContentBody`. `ContentHeader` nunca fica
19
+ solto. `title`, `description`, `meta` e `actions` no `Content` são a abreviação para o caso
20
+ direto e não podem ser misturados ao header explícito. `level` preserva a hierarquia semântica
21
+ do heading.
22
+ - Card, Drawer e Pane nomeiam a região principal como `CardBody`, `DrawerBody` e `PaneBody`.
23
+ `*Content` permanece reservado a raízes técnicas ou painéis cujo papel não é o corpo de uma
24
+ estrutura, como `DialogContent`, `PopoverContent` e `TabsContent`.
13
25
  - Componentes compartilhados não impõem margem externa; páginas e shells compõem layout.
14
26
  - A fonte raiz pertence ao navegador e à aplicação. Medidas escaláveis usam `rem` ou a escala
15
27
  relativa do Tailwind; `px` fica restrito a hairlines e compensações ligadas a essas bordas.
@@ -55,18 +67,23 @@
55
67
  valor trunca no trigger e a opção inteira fica na lista. Não dimensionar filtro pelo conteúdo
56
68
  nem pela label; o modal usa `w-full`.
57
69
  - Catálogo e API efetivos vêm dos exports da versão instalada, não de memória ou exemplo antigo.
70
+ - Em componentes semânticos, `context` responde por que há destaque e `variant` responde como ele
71
+ aparece. O vocabulário canônico é `neutral | primary | info | success | warning | danger`; as
72
+ variantes visuais são `solid | subtle | outline | ghost | link`, limitadas por componente.
73
+ `light`/`dark` são temas, `secondary` não substitui estado neutro e `destructive` é comportamento
74
+ de action projetado visualmente como `danger`.
58
75
 
59
76
  ## Dicionários e dimensões
60
77
 
61
78
  O dicionário declara o papel; a tela só escolhe onde o valor fica. Tabela de decisão aplicada
62
79
  por `DictionaryValue` e pelas colunas de `ActionList`:
63
80
 
64
- | Papel declarado | Exemplos | Forma | Variante | Ícone | Tooltip |
65
- |---|---|---|---|---|---|
66
- | `classification` | Tipo de cliente, categoria, natureza | Badge | `outline`; ignora `tone` | se a entrada declara `icon` do catálogo | se `description` acrescenta ao rótulo |
67
- | `status` | Aberto, resolvido, degradado | Badge | tonal pelo `tone`; `neutral` sem tom; nunca `outline` | idem | idem |
68
- | `stage` | Prospect, cliente; etapa do funil | Badge | igual a `status` | idem | idem |
69
- | `plain` ou ausente | Fonte, formato, período | Texto | — | idem | idem |
81
+ | Papel declarado | Exemplos | Forma | Contexto | Variante | Ícone | Tooltip |
82
+ |---|---|---|---|---|---|---|
83
+ | `classification` | Tipo de cliente, categoria, natureza | Badge | `neutral` | `outline`; ignora `context` da entrada | se a entrada declara `icon` do catálogo | se `description` acrescenta ao rótulo |
84
+ | `status` | Aberto, resolvido, degradado | Badge | pela entrada; `neutral` por padrão | `subtle`; nunca `outline` | idem | idem |
85
+ | `stage` | Prospect, cliente; etapa do funil | Badge | igual a `status` | `subtle` | idem | idem |
86
+ | `plain` ou ausente | Fonte, formato, período | Texto | — | — | idem | idem |
70
87
 
71
88
  Regras que não dependem da tabela:
72
89
 
@@ -88,7 +105,7 @@ export const customerKindDict = t.dict(
88
105
  { doc: 'Natureza da parte no cadastro global.', presentation: 'classification' },
89
106
  )
90
107
  export const customerStageDict = t.dict(
91
- { prospect: { label: 'Prospect' }, customer: { label: 'Cliente', tone: 'success' } },
108
+ { prospect: { label: 'Prospect' }, customer: { label: 'Cliente', context: 'success' } },
92
109
  { doc: 'Estágio comercial atual da parte.', presentation: 'stage' },
93
110
  )
94
111
  // contrato:
@@ -112,7 +129,7 @@ cells={{
112
129
  ),
113
130
  stage: (item) =>
114
131
  item.stage === 'customer'
115
- ? <Badge variant="secondary">Cliente</Badge>
132
+ ? <Badge context="neutral" variant="solid">Cliente</Badge>
116
133
  : <Badge variant="outline">Prospect</Badge>,
117
134
  }}
118
135
 
@@ -124,7 +141,13 @@ cells={{
124
141
 
125
142
  // Tooltip que repete o rótulo; cor como único sinal.
126
143
  <Tooltip>
127
- <TooltipTrigger><Dot variant="success" /></TooltipTrigger>
144
+ <TooltipTrigger><Dot context="success" /></TooltipTrigger>
128
145
  <TooltipContent>Cliente</TooltipContent>
129
146
  </Tooltip>
147
+
148
+ // Contexto semântico usado como variante: a IA perdeu um eixo da API.
149
+ <Badge variant="success">Concluído</Badge>
150
+
151
+ // Risco comportamental usado como nome visual.
152
+ <Button variant="destructive">Excluir</Button>
130
153
  ```
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: maintain-opus-docs
3
+ description: Cria, reorganiza e revisa a documentação publicada do Opus, incluindo páginas conceituais, famílias de componentes, exemplos vivos, props, navegação e redirects. Use ao documentar ou revisar o catálogo e os guias de @softize/opus.
4
+ ---
5
+
6
+ # Manter documentação Opus
7
+
8
+ ## Resultado
9
+
10
+ Entregar documentação que ajuda a pessoa a escolher e usar o recurso pelo caminho canônico,
11
+ preserva a relação entre páginas, catálogo e API pública e continua verificável pelos gates do
12
+ repositório.
13
+
14
+ ## Entradas
15
+
16
+ Identificar o público, a tarefa que levou a pessoa à página e o conjunto de APIs públicas coberto.
17
+ Ler [padrão editorial](references/editorial-standard.md) antes de escrever. Inspecionar o componente,
18
+ seus testes, metadata, exportações e páginas relacionadas; a documentação não define um contrato que
19
+ o código não sustenta.
20
+
21
+ ## Procedimento
22
+
23
+ 1. Inventariar as páginas, componentes e rotas afetadas antes de alterar a organização.
24
+ 2. Decidir a unidade da página pelo conceito ensinado. Manter componentes compostos da mesma família
25
+ na mesma página quando compartilham decisão de uso e vocabulário; separar conceitos independentes.
26
+ 3. Conduzir a leitura do caso comum para o específico: situação reconhecível, escolha recomendada,
27
+ exemplo mínimo, composição, variações, comportamentos e referência.
28
+ 4. Escrever cada seção para funcionar por link direto, repetindo apenas o contexto indispensável.
29
+ 5. Usar exemplos pequenos, executáveis e coerentes entre si. Explicar antes o que observar e depois
30
+ o comportamento automático ou a consequência que não esteja evidente no código.
31
+ 6. Manter uma tabela de propriedades identificada para cada componente público coberto pela página.
32
+ Não usar uma tabela genérica para contratos diferentes.
33
+ 7. Ao renomear ou agrupar páginas, atualizar registry, metadata, navegação e links; preservar slugs
34
+ publicados por redirect ou alias quando o endereço canônico mudar.
35
+ 8. Reler todo o texto no fluxo renderizado e aplicar o checklist do padrão editorial linha por linha.
36
+ 9. Atualizar testes, inventário de copy e projeções afetadas pelo mesmo conjunto de mudanças.
37
+
38
+ ## Decisões
39
+
40
+ - A página ensina uma decisão de uso; a tabela de props documenta o contrato. Nenhuma substitui a
41
+ outra.
42
+ - O exemplo canônico aparece antes da enumeração de possibilidades. Alternativas entram no ponto em
43
+ que a pessoa precisa escolher entre elas.
44
+ - Defaults, efeitos automáticos, limites e riscos ficam próximos do exemplo em que se tornam
45
+ relevantes.
46
+ - Páginas conceituais podem ser extensas quando constroem um fluxo completo; páginas de componente
47
+ permanecem compactas e usam previews para carregar parte da explicação.
48
+ - Inspiração editorial externa orienta progressão e clareza, não autoriza copiar texto, idioma,
49
+ personalidade promocional ou convenções incompatíveis com o Opus.
50
+
51
+ ## Verificação
52
+
53
+ Executar `node scripts/audit-docs.mjs "$(git rev-parse --show-toplevel)"` a partir do diretório
54
+ desta skill e, depois, os testes do renderer e do catálogo, typecheck, `opus check` e
55
+ `opus copy --check`. Conferir
56
+ que todos os previews renderizam, que cada API pública documentada possui sua própria referência,
57
+ que nenhum arquivo publicado ficou órfão e que links e redirects chegam à página esperada. Fazer uma
58
+ passada visual nas páginas alteradas e registrar qualquer limitação que o gate automático não cubra.
59
+
60
+ ## Saída
61
+
62
+ Informar páginas criadas, agrupadas ou reescritas, decisões editoriais aplicadas, verificações
63
+ executadas e pendências reais. Em revisão ampla, fornecer o inventário coberto para tornar explícito
64
+ o significado de “toda a documentação”.
65
+
66
+ ## Limites
67
+
68
+ - Não inventar comportamento, prop, default ou recomendação a partir do nome do componente.
69
+ - Não transformar a documentação em sequência de tabelas nem antecipar a referência antes do modelo
70
+ mental necessário.
71
+ - Não criar uma página por exportação quando os símbolos formam uma única família de uso.
72
+ - Não esconder APIs públicas de uma família em uma tabela de props compartilhada.
73
+ - Não editar projeção gerada quando existe fonte canônica.
74
+ - Não promover alteração de documentação a release, publicação ou push sem autorização específica.
75
+
76
+ ## Recursos
77
+
78
+ - Ler [padrão editorial](references/editorial-standard.md) para anatomia, tom e revisão linha por
79
+ linha.
80
+ - Usar [avaliações](references/evaluations.md) ao criar ou alterar substancialmente esta skill.
81
+ - Usar `scripts/audit-docs.mjs [raiz-do-repositório]` para detectar páginas órfãs, fences
82
+ incompletos, saltos de heading e nomes genéricos de referência. O script complementa a leitura;
83
+ não decide clareza, progressão ou exatidão técnica.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Manter documentação Opus"
3
+ short_description: "Escreve e revisa as docs publicadas do Opus"
4
+ default_prompt: "Use $maintain-opus-docs para revisar esta documentação do Opus."
@@ -0,0 +1,85 @@
1
+ # Padrão editorial da documentação Opus
2
+
3
+ ## Anatomia da página
4
+
5
+ Adotar a menor sequência que forme o modelo mental necessário:
6
+
7
+ 1. **Situação e escolha:** dizer o que o recurso resolve e quando escolhê-lo. Contrastar com o
8
+ componente vizinho apenas quando essa distinção evita uma decisão errada.
9
+ 2. **Exemplo canônico:** mostrar o menor uso realista e funcional antes das opções.
10
+ 3. **Composição:** nomear as partes públicas e explicar a relação entre elas.
11
+ 4. **Variações:** introduzir uma variação por necessidade observável, não por enumeração da API.
12
+ 5. **Comportamentos e cuidados:** explicitar defaults, efeitos automáticos, acessibilidade, limites e
13
+ consequências perto do exemplo relevante.
14
+ 6. **Referência:** terminar com uma seção identificada por componente público, sem fundir contratos
15
+ diferentes numa única tabela.
16
+
17
+ Nem toda página precisa de todas as seções. Remover a seção vazia em vez de preenchê-la com prosa
18
+ genérica.
19
+
20
+ ## Voz
21
+
22
+ - Partir do objetivo da pessoa: “Use `Alert` para manter uma informação visível no contexto da
23
+ página.”
24
+ - Preferir verbo concreto e voz ativa: “O `PageHeader` organiza título e ações.”
25
+ - Apresentar o caminho recomendado com segurança; usar “pode” somente quando a alternativa é de
26
+ fato opcional.
27
+ - Introduzir termos técnicos em linguagem comum antes de depender deles.
28
+ - Manter tom próximo, sóbrio e profissional. Evitar propaganda, slogans, superlativos e entusiasmo
29
+ artificial.
30
+ - Evitar começar pela implementação: substituir “O componente é responsável por renderizar...”
31
+ pela decisão ou resultado que importa a quem usa.
32
+ - Usar frases e parágrafos curtos, sem fragmentar relações necessárias nem recorrer a abreviações.
33
+
34
+ ## Exemplos
35
+
36
+ - Preparar o exemplo com uma frase que indique o objetivo ou o que deve ser observado.
37
+ - Manter exemplos executáveis, focados e coerentes com o caminho recomendado.
38
+ - Preferir uma pequena narrativa contínua a exemplos isolados que trocam de domínio sem necessidade.
39
+ - Não demonstrar combinações inválidas apenas para listar props.
40
+ - Depois do código, explicar somente efeitos que não sejam óbvios pela leitura: default aplicado,
41
+ estado controlado, ação automática, limite ou consequência.
42
+ - Usar preview para comportamento visual e bloco de código para integração sem palco executável.
43
+
44
+ ## Famílias e referência
45
+
46
+ - Agrupar componentes quando a pessoa precisa compreendê-los em conjunto para realizar uma tarefa,
47
+ como `Button` e `ButtonGroup` ou `Page`, `PageHeader`, `PageBody` e `PageState`.
48
+ - Manter títulos e âncoras explícitos para cada membro da família.
49
+ - Criar `## Propriedades de ComponentName` para cada componente público que possui contrato próprio.
50
+ - Omitir tabela apenas para export sem props próprias ou alias cuja equivalência esteja declarada.
51
+ - Posicionar tipos compartilhados depois dos componentes que os utilizam ou numa seção claramente
52
+ nomeada.
53
+
54
+ ## Links e navegação
55
+
56
+ - Inserir links no ponto da decisão: ao recomendar `Toast` como alternativa efêmera, ligar a palavra
57
+ à página correspondente.
58
+ - Não depender de uma seção genérica de “Veja também” para relações essenciais.
59
+ - Ao consolidar páginas, escolher um endereço canônico e preservar os anteriores com redirect.
60
+ - Conferir título visível, slug, registry, metadata e links como uma única identidade editorial.
61
+
62
+ ## Revisão linha por linha
63
+
64
+ Para cada título, parágrafo, item, exemplo e célula de tabela, verificar:
65
+
66
+ 1. A pessoa entende por que esta linha existe neste ponto da leitura?
67
+ 2. A linha começa pela necessidade ou introduz detalhe interno cedo demais?
68
+ 3. A afirmação é sustentada pelo código, teste ou decisão registrada?
69
+ 4. Está claro se é default, obrigação, recomendação, alternativa ou exceção?
70
+ 5. Há termo ainda não apresentado, pronome ambíguo ou contexto que só existe na cabeça de quem
71
+ implementou?
72
+ 6. A frase pode ficar menor sem perder relação, condição ou consequência?
73
+ 7. O exemplo mostra o caminho recomendado e continua compilável?
74
+ 8. O texto ao redor do exemplo explica intenção e comportamento, sem narrar cada linha do código?
75
+ 9. O título permite localizar a informação pela tarefa, inclusive por link direto?
76
+ 10. Pontuação, capitalização, concordância e paralelismo estão consistentes?
77
+
78
+ Ao terminar cada página, reler a sequência inteira. Linhas corretas isoladamente ainda podem formar
79
+ uma página repetitiva, invertida ou sem progressão.
80
+
81
+ ## Referência de estilo
82
+
83
+ O padrão absorve da documentação do Laravel a progressão do caso comum para os detalhes, os exemplos
84
+ como eixo narrativo, a explicação dos comportamentos automáticos e a navegação por decisões. O Opus
85
+ mantém sua própria voz em pt-BR: mais compacta, menos promocional e apoiada em previews visuais.
@@ -0,0 +1,34 @@
1
+ # Avaliações
2
+
3
+ ## Deve disparar
4
+
5
+ “Agrupe Button Group na página de Button, preserve a rota antiga e documente as props dos dois.”
6
+
7
+ “Revise toda a documentação publicada do Opus linha por linha e corrija a escrita.”
8
+
9
+ ## Não deve disparar
10
+
11
+ “Escreva a regra de reembolso na documentação interna do produto.” Esse texto não pertence à
12
+ documentação publicada do SDK Opus.
13
+
14
+ “Corrija o alinhamento do ícone no Alert.” Uma mudança somente no componente pertence à
15
+ implementação de UI; esta skill entra apenas se a documentação também for criada ou alterada.
16
+
17
+ ## Execução real
18
+
19
+ Fornecer uma página de família que começa pela lista completa de props, usa a mesma tabela para dois
20
+ componentes, mantém exemplos isolados sem objetivo, descreve implementação antes da decisão de uso e
21
+ remove a rota publicada do componente agrupado. Pedir a reorganização sem informar a resposta
22
+ esperada.
23
+
24
+ Aprovar somente quando a página começar pela situação e escolha, apresentar um exemplo canônico
25
+ executável, explicar defaults ou consequências no ponto relevante, criar referência identificada
26
+ para cada contrato público e preservar a rota anterior por redirect ou alias. Exigir que a escrita
27
+ seja próxima, direta e sóbria, sem copiar formulações da referência externa nem adotar tom
28
+ promocional.
29
+
30
+ Na revisão ampla, fornecer registry, metadata, componentes, testes e todas as páginas publicadas.
31
+ Exigir inventário explícito, leitura linha por linha, correção na fonte canônica, verificação dos
32
+ previews, typecheck, gates de copy e confirmação de que não restaram páginas órfãs. Reprovar se a
33
+ execução se limitar às páginas mais longas, fizer apenas busca por padrões ou declarar cobertura
34
+ total sem listar o universo revisado.
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+
6
+ const repoRoot = resolve(process.argv[2] ?? process.cwd());
7
+ const contentDir = resolve(repoRoot, "packages/opus/src/ui/docs/content");
8
+ const registryPath = resolve(repoRoot, "packages/opus/src/ui/docs/registry.tsx");
9
+
10
+ if (!existsSync(contentDir) || !existsSync(registryPath)) {
11
+ console.error(
12
+ "Não encontrei packages/opus/src/ui/docs/content e registry.tsx. Passe a raiz do repositório Opus.",
13
+ );
14
+ process.exit(2);
15
+ }
16
+
17
+ const registry = readFileSync(registryPath, "utf8");
18
+ const importedFiles = new Set(
19
+ [...registry.matchAll(/\.\/content\/([^"']+\.md)\?raw/g)].map((match) => match[1]),
20
+ );
21
+ const files = readdirSync(contentDir)
22
+ .filter((file) => file.endsWith(".md"))
23
+ .sort();
24
+ const findings = [];
25
+
26
+ for (const file of files) {
27
+ const source = readFileSync(resolve(contentDir, file), "utf8");
28
+ const lines = source.split("\n");
29
+
30
+ if (!importedFiles.has(file)) {
31
+ findings.push(`${file}: página órfã; não há import no registry`);
32
+ }
33
+
34
+ let inFence = false;
35
+ let previousHeading = 0;
36
+ for (let index = 0; index < lines.length; index += 1) {
37
+ const line = lines[index];
38
+ const lineNumber = index + 1;
39
+
40
+ if (/^```/.test(line)) {
41
+ inFence = !inFence;
42
+ continue;
43
+ }
44
+ if (inFence) continue;
45
+
46
+ const heading = /^(#{1,6})\s+/.exec(line);
47
+ if (heading) {
48
+ const level = heading[1].length;
49
+ if (previousHeading > 0 && level > previousHeading + 1) {
50
+ findings.push(`${file}:${lineNumber}: heading salta de h${previousHeading} para h${level}`);
51
+ }
52
+ previousHeading = level;
53
+ }
54
+
55
+ if (/^#{2,6}\s+Props(?:\s|$)/i.test(line)) {
56
+ findings.push(`${file}:${lineNumber}: nomeie a referência como “Propriedades de Componente”`);
57
+ }
58
+ if (/^\|\s*Prop\s*\|/i.test(line) || /\|\s*Default\s*\|/.test(line)) {
59
+ findings.push(`${file}:${lineNumber}: use “Propriedade” e “Padrão” no cabeçalho da tabela`);
60
+ }
61
+ if (/\b(?:pra|pro|pros|numa)\b/i.test(line)) {
62
+ findings.push(`${file}:${lineNumber}: abreviação coloquial na prosa`);
63
+ }
64
+ }
65
+
66
+ if (inFence) findings.push(`${file}: fence de código sem fechamento`);
67
+ }
68
+
69
+ for (const importedFile of importedFiles) {
70
+ if (!files.includes(importedFile)) {
71
+ findings.push(`${importedFile}: importado pelo registry, mas o arquivo não existe`);
72
+ }
73
+ }
74
+
75
+ if (findings.length > 0) {
76
+ console.error(findings.join("\n"));
77
+ console.error(`\n${findings.length} problema(s) estrutural(is) encontrado(s).`);
78
+ process.exit(1);
79
+ }
80
+
81
+ console.log(`${files.length} páginas auditadas; nenhuma inconsistência estrutural encontrada.`);
@@ -35,7 +35,8 @@ da mesma instância, sem catálogo repetido em enum, opção estática ou format
35
35
  - **status** — situação operacional que muda com o tempo;
36
36
  - **stage** — etapa de um ciclo ou funil;
37
37
  - **plain** — valor que só precisa ser legível (o mesmo efeito de omitir).
38
- Por entrada, declarar `tone` somente em status e estágio, `icon` somente com nome existente no
38
+ Por entrada, declarar `context` somente em status e estágio, usando `neutral`, `info`, `success`,
39
+ `warning` ou `danger`; `icon` somente com nome existente no
39
40
  catálogo `iconPickerIcons`, e `description` somente quando acrescentar algo ao rótulo. `doc`
40
41
  continua sendo o entendimento de negócio para manifest e Lens; não é tooltip.
41
42
  4. Derivar o schema por `.zod()` e usá-lo em todo contrato que valide o código; não redeclarar a
@@ -68,7 +69,8 @@ contrato ou componente mapeado, regenerar com `opus copy` e executar os checks d
68
69
  - Não tratar metadata de dicionário como autorização ou invariante de integridade.
69
70
  - Não omitir `presentation` esperando que a tela deduza o papel pelo nome do dicionário; sem
70
71
  papel declarado, o valor é texto.
71
- - Não declarar `tone` em classificação, nem `icon` fora do catálogo, nem `description` que
72
+ - Não declarar `context` em classificação, nem usar o alias legado `tone` em código novo, nem
73
+ `icon` fora do catálogo, nem `description` que
72
74
  repita o rótulo.
73
75
 
74
76
  ## Recursos
@@ -11,8 +11,9 @@
11
11
  interface lê rótulos por `labelFor`/`metaFor`.
12
12
  - Execução de apresentação: dado um cadastro com “Pessoa física/Empresa” e “Prospect/Cliente”,
13
13
  declarar o primeiro como `classification` com ícones `user` e `building` do catálogo e o segundo
14
- como `stage` com `tone` explícito, sem `description` que repita o rótulo; provar que o manifest
15
- projeta `presentation` e que `t.dict` rejeita `presentation` ou `tone` fora do vocabulário.
16
- - Reprova: declarar `tone` em uma classificação, inventar `icon` fora do catálogo, copiar `doc`
14
+ como `stage` com `context` explícito, sem `description` que repita o rótulo; provar que o manifest
15
+ projeta `presentation` e `context` e que `t.dict` rejeita valores fora do vocabulário.
16
+ - Reprova: declarar `context` em uma classificação, usar o alias legado `tone` em código novo,
17
+ inventar `icon` fora do catálogo, copiar `doc`
17
18
  para `description` ou deixar `presentation` ausente em um status esperando que a tela infira o
18
19
  badge.
@@ -26,7 +26,7 @@ export function App(): React.ReactElement {
26
26
  {items.map((t) => (
27
27
  <li key={t.id} className="flex items-center justify-between gap-2 text-sm">
28
28
  <span>{t.title}</span>
29
- <Badge variant={t.done ? 'default' : 'secondary'}>{t.done ? 'Feita' : 'Aberta'}</Badge>
29
+ <Badge context={t.done ? 'success' : 'neutral'}>{t.done ? 'Feita' : 'Aberta'}</Badge>
30
30
  </li>
31
31
  ))}
32
32
  </ul>