@softize/opus 13.0.0 → 14.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 (164) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/PROMOTED.md +46 -0
  3. package/README.md +28 -19
  4. package/bin/cli.mjs +87 -216
  5. package/bin/lib/cli-shared.mjs +131 -0
  6. package/bin/lib/copy.mjs +276 -6
  7. package/bin/lib/db.mjs +16 -74
  8. package/bin/lib/gen-openapi.mjs +3 -3
  9. package/bin/lib/gen-runner.mjs +1 -1
  10. package/bin/lib/gen.mjs +14 -69
  11. package/bin/lib/mcp.mjs +3 -1
  12. package/bin/lib/seed.mjs +5 -62
  13. package/docs/code-style.md +4 -1
  14. package/docs/ownership-vs-shadcn-lock.md +2 -3
  15. package/docs/protocol.md +7 -7
  16. package/docs/releasing.md +8 -2
  17. package/package.json +7 -3
  18. package/registry/instructions/opus.md +3 -3
  19. package/registry/templates/app/package.json +1 -1
  20. package/registry/templates/app/src/App.tsx +11 -6
  21. package/registry/templates/app/src/main.tsx +4 -4
  22. package/src/audit/drivers/console.ts +1 -0
  23. package/src/auth/drivers/better-auth.ts +1 -0
  24. package/src/auth/drivers/jwt.ts +1 -0
  25. package/src/cache/drivers/memory.ts +1 -0
  26. package/src/client/drivers/fetch.ts +2 -1
  27. package/src/core/actions.ts +6 -1
  28. package/src/core/audit.ts +9 -3
  29. package/src/core/contracts.ts +7 -0
  30. package/src/core/domain.ts +1 -1
  31. package/src/core/errors.ts +18 -15
  32. package/src/core/index.ts +4 -2
  33. package/src/core/package-version.ts +26 -0
  34. package/src/core/reactions.ts +1 -1
  35. package/src/core/runtime.ts +33 -23
  36. package/src/core/schedules.ts +1 -1
  37. package/src/core/types.ts +5 -6
  38. package/src/dsl/eval.ts +2 -2
  39. package/src/dsl/kysely.ts +2 -2
  40. package/src/dsl/loads.ts +1 -1
  41. package/src/dsl/parser.ts +5 -5
  42. package/src/events/drivers/mitt.ts +1 -0
  43. package/src/mcp/index.ts +2 -1
  44. package/src/observability/drivers/opentelemetry.ts +1 -0
  45. package/src/queue/drivers/bullmq.ts +3 -3
  46. package/src/scheduler/drivers/node-cron.ts +3 -2
  47. package/src/scheduler/every.ts +7 -7
  48. package/src/schema/openapi.ts +3 -3
  49. package/src/seed/index.ts +29 -0
  50. package/src/server/drivers/fastify.ts +5 -2
  51. package/src/server/drivers/node.ts +9 -6
  52. package/src/server/index.ts +3 -1
  53. package/src/storage/drivers/fs.ts +1 -0
  54. package/src/testing/index.ts +3 -3
  55. package/src/ui/components/patterns/action-list-dialog.tsx +10 -3
  56. package/src/ui/components/patterns/confirm.tsx +2 -31
  57. package/src/ui/components/patterns/content-header.tsx +44 -137
  58. package/src/ui/components/patterns/data-state.tsx +42 -68
  59. package/src/ui/components/patterns/dock.tsx +20 -3
  60. package/src/ui/components/patterns/form.tsx +26 -22
  61. package/src/ui/components/patterns/list.tsx +18 -12
  62. package/src/ui/components/patterns/page-state.tsx +39 -51
  63. package/src/ui/components/patterns/page.tsx +37 -54
  64. package/src/ui/components/patterns/sidebar.tsx +17 -6
  65. package/src/ui/components/patterns/state-surface.tsx +148 -0
  66. package/src/ui/components/patterns/surface-header.tsx +119 -0
  67. package/src/ui/components/patterns/trigger.tsx +21 -25
  68. package/src/ui/components/patterns/view.tsx +29 -22
  69. package/src/ui/components/primitives/alert.tsx +1 -27
  70. package/src/ui/components/primitives/ask.tsx +3 -3
  71. package/src/ui/components/primitives/avatar.tsx +15 -5
  72. package/src/ui/components/primitives/badge.tsx +5 -41
  73. package/src/ui/components/primitives/breadcrumb.tsx +2 -2
  74. package/src/ui/components/primitives/button.tsx +39 -30
  75. package/src/ui/components/primitives/calendar.tsx +28 -2
  76. package/src/ui/components/primitives/carousel.tsx +3 -3
  77. package/src/ui/components/primitives/chat.tsx +1 -1
  78. package/src/ui/components/primitives/checkbox.tsx +1 -1
  79. package/src/ui/components/primitives/command.tsx +2 -2
  80. package/src/ui/components/primitives/control.ts +72 -0
  81. package/src/ui/components/primitives/copyable.tsx +1 -1
  82. package/src/ui/components/primitives/dialog.tsx +12 -7
  83. package/src/ui/components/primitives/dot.tsx +1 -25
  84. package/src/ui/components/primitives/drawer.tsx +10 -3
  85. package/src/ui/components/primitives/field.tsx +3 -3
  86. package/src/ui/components/primitives/icon-picker.tsx +3 -1
  87. package/src/ui/components/primitives/input-group.tsx +12 -9
  88. package/src/ui/components/primitives/input-otp.tsx +1 -1
  89. package/src/ui/components/primitives/input.tsx +2 -2
  90. package/src/ui/components/primitives/item.tsx +3 -1
  91. package/src/ui/components/primitives/menu.tsx +1 -7
  92. package/src/ui/components/primitives/pagination.tsx +16 -8
  93. package/src/ui/components/primitives/progress.tsx +32 -3
  94. package/src/ui/components/primitives/radio-group.tsx +1 -1
  95. package/src/ui/components/primitives/resizable.tsx +3 -1
  96. package/src/ui/components/primitives/select.tsx +6 -6
  97. package/src/ui/components/primitives/slider.tsx +5 -1
  98. package/src/ui/components/primitives/sonner.tsx +3 -0
  99. package/src/ui/components/primitives/spinner.tsx +13 -16
  100. package/src/ui/components/primitives/switch.tsx +5 -1
  101. package/src/ui/components/primitives/tabs.tsx +6 -3
  102. package/src/ui/components/primitives/textarea.tsx +1 -1
  103. package/src/ui/components/primitives/toggle.tsx +9 -4
  104. package/src/ui/components/primitives/tooltip.tsx +1 -0
  105. package/src/ui/docs/changelog.tsx +1 -1
  106. package/src/ui/docs/content/action-form.md +36 -3
  107. package/src/ui/docs/content/action-list-dialog.md +2 -2
  108. package/src/ui/docs/content/action-list.md +13 -2
  109. package/src/ui/docs/content/action-trigger.md +12 -5
  110. package/src/ui/docs/content/action-view.md +11 -3
  111. package/src/ui/docs/content/ask.md +11 -0
  112. package/src/ui/docs/content/avatar.md +7 -3
  113. package/src/ui/docs/content/button.md +30 -14
  114. package/src/ui/docs/content/calendar.md +13 -0
  115. package/src/ui/docs/content/card.md +26 -0
  116. package/src/ui/docs/content/chat.md +20 -0
  117. package/src/ui/docs/content/cli.md +71 -19
  118. package/src/ui/docs/content/communication.md +36 -0
  119. package/src/ui/docs/content/composer.md +15 -0
  120. package/src/ui/docs/content/content.md +17 -1
  121. package/src/ui/docs/content/copyable.md +8 -0
  122. package/src/ui/docs/content/data-state.md +17 -13
  123. package/src/ui/docs/content/detail.md +19 -1
  124. package/src/ui/docs/content/dialog.md +1 -4
  125. package/src/ui/docs/content/dictionary-value.md +9 -2
  126. package/src/ui/docs/content/dock.md +8 -0
  127. package/src/ui/docs/content/dot.md +8 -0
  128. package/src/ui/docs/content/empty.md +2 -2
  129. package/src/ui/docs/content/getting-started.md +2 -2
  130. package/src/ui/docs/content/icon-picker.md +11 -0
  131. package/src/ui/docs/content/input.md +1 -1
  132. package/src/ui/docs/content/item.md +1 -1
  133. package/src/ui/docs/content/label.md +7 -0
  134. package/src/ui/docs/content/menu.md +6 -0
  135. package/src/ui/docs/content/metric-card.md +13 -0
  136. package/src/ui/docs/content/page.md +20 -4
  137. package/src/ui/docs/content/pagination.md +11 -9
  138. package/src/ui/docs/content/popover.md +6 -0
  139. package/src/ui/docs/content/progress.md +8 -11
  140. package/src/ui/docs/content/select.md +5 -5
  141. package/src/ui/docs/content/semantic-context.md +5 -4
  142. package/src/ui/docs/content/sidebar.md +13 -47
  143. package/src/ui/docs/content/skeleton.md +6 -0
  144. package/src/ui/docs/content/spinner.md +9 -6
  145. package/src/ui/docs/content/split.md +21 -0
  146. package/src/ui/docs/content/switch.md +1 -1
  147. package/src/ui/docs/content/tabs.md +1 -1
  148. package/src/ui/docs/content/textarea.md +7 -0
  149. package/src/ui/docs/content/toggle.md +1 -1
  150. package/src/ui/docs/content/tokens.md +4 -4
  151. package/src/ui/docs/content/truncate.md +8 -0
  152. package/src/ui/docs/content/ui.md +14 -0
  153. package/src/ui/docs/doc-client.tsx +5 -5
  154. package/src/ui/docs/doc.tsx +26 -14
  155. package/src/ui/docs/registry.tsx +5 -5
  156. package/src/ui/docs/standalone.tsx +2 -2
  157. package/src/ui/drivers/react.tsx +12 -12
  158. package/src/ui/lib/action-errors.ts +45 -0
  159. package/src/ui/lib/zod-pt-br.ts +31 -4
  160. package/src/ui/meta.ts +8 -8
  161. package/src/ui/react.tsx +10 -16
  162. package/src/ui/theme.css +10 -8
  163. package/src/vite/design.ts +6 -18
  164. package/src/ui/components/patterns/shell-nav.tsx +0 -147
@@ -28,10 +28,14 @@ para agente.
28
28
 
29
29
  ## Tamanhos
30
30
 
31
- size sm/default/lg o fallback acompanha o tamanho. sm para listas densas, lg para cabeçalho de
32
- workspace.
31
+ `size` usa a escala única dos controles: o avatar de uma linha mede o mesmo que o controle ao lado
32
+ (`sm` 2rem, `default` 2.25rem, `lg` 2.5rem); `xs` (1.5rem) é a lista densa. O fallback e o selo
33
+ acompanham o tamanho.
33
34
 
34
35
  ```tsx preview
36
+ <Avatar size="xs">
37
+ <AvatarFallback>AL</AvatarFallback>
38
+ </Avatar>
35
39
  <Avatar size="sm">
36
40
  <AvatarFallback>AL</AvatarFallback>
37
41
  </Avatar>
@@ -86,7 +90,7 @@ excedente — os membros do workspace Empresa X.
86
90
 
87
91
  | Propriedade | Tipo | Padrão | Descrição |
88
92
  |---|---|---|---|
89
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Diâmetro do retrato; o fallback e o selo acompanham a escala. |
93
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'default'` | Diâmetro do retrato na escala única dos controles (1.5 · 2 · 2.25 · 2.5rem); o fallback e o selo acompanham. |
90
94
 
91
95
  ## Propriedades de AvatarImage
92
96
 
@@ -2,8 +2,7 @@
2
2
 
3
3
  `context` declara a hierarquia ou o risco da ação; `variant` escolhe o tratamento visual. Use
4
4
  `primary` para a ação principal, `neutral` para ações de apoio e `danger` quando a ação tiver uma
5
- consequência perigosa. `default`, `secondary` e `destructive` permanecem apenas como aliases de
6
- compatibilidade.
5
+ consequência perigosa.
7
6
 
8
7
  ```tsx preview
9
8
  <Button>Criar workspace</Button>
@@ -16,28 +15,45 @@ compatibilidade.
16
15
 
17
16
  ## Tamanhos
18
17
 
19
- O tamanho icon exige `aria-label`, porque não texto visível. Os botões só-ícone vêm em três tamanhos: `icon` (2.25rem), `icon-sm` (2rem, para uma fileira densa como o cabeçalho) e `icon-xs` (1.5rem, para uma ação dentro de um campo, como o `trailing` de Input ou Select).
18
+ `size` usa a escala única dos controles: o mesmo nome tem a mesma medida em `Button`, `Select`,
19
+ `Tabs`, `Toggle`, `Switch`, `Avatar`, `Spinner` e nos botões embutidos. Os tamanhos de texto dão a
20
+ altura da linha; os `icon-*` são quadrados para botões só de ícone, que exigem `aria-label` porque não
21
+ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em `xs` e `sm`, 1rem em
22
+ `default`, 1.25rem em `lg`), a menos que o ícone traga um `size-*` próprio.
23
+
24
+ | Nome | Medida | Uso |
25
+ |---|---|---|
26
+ | `xs` | 1.5rem | Ação dentro de um campo (`InputGroupButton`). |
27
+ | `sm` | 2rem | Toolbar e cabeçalho densos, ao lado de `Select` e `Tabs` `sm`. |
28
+ | `default` | 2.25rem | A linha padrão, a mesma de `Input`. |
29
+ | `lg` | 2.5rem | Chamada principal com mais área de toque. |
30
+ | `icon-xs` | 1.5rem | Ação só de ícone dentro de um campo, como o `trailing` de Input ou Select. |
31
+ | `icon-sm` | 1.75rem | Ação só de ícone dentro de uma linha ou card; é o quadrado de `ActionTrigger` com `icon` e das setas do pager de `ActionList`. |
32
+ | `icon` | 2.25rem | Ação só de ícone na linha padrão. |
33
+ | `icon-lg` | 2.5rem | Ação só de ícone ao lado de um `lg`. |
20
34
 
21
35
  ```tsx preview
36
+ <Button size="xs">Mínimo</Button>
22
37
  <Button size="sm">Pequeno</Button>
23
38
  <Button>Padrão</Button>
24
39
  <Button size="lg">Grande</Button>
25
- <Button size="icon" aria-label="Novo"><Plus /></Button>
26
- <Button size="icon-sm" variant="ghost" aria-label="Novo"><Plus /></Button>
27
40
  <Button size="icon-xs" variant="ghost" aria-label="Novo"><Plus /></Button>
41
+ <Button size="icon-sm" variant="ghost" aria-label="Novo"><Plus /></Button>
42
+ <Button size="icon" aria-label="Novo"><Plus /></Button>
43
+ <Button size="icon-lg" aria-label="Novo"><Plus /></Button>
28
44
  ```
29
45
 
30
46
  ## Estados
31
47
 
32
- busy = ação em andamento (DEPOIS do clique): o Spinner e o disabled vêm do botão. Com icon, o
33
- Spinner TROCA o ícone (não soma). Não confunda com carregar conteúdo (ANTES) — isso é Spinner
34
- centralizado/Skeleton em um nível de página.
48
+ busy = ação em andamento (DEPOIS do clique): o Spinner e o disabled vêm do botão. `icon` recebe o
49
+ elemento do ícone e o dimensiona pelo `size`; com icon, o Spinner TROCA o ícone (não soma). Não
50
+ confunda com carregar conteúdo (ANTES) — isso é `DataState` ou `Skeleton` em um nível de página.
35
51
 
36
52
  ```tsx preview
37
53
  <Button disabled>Desabilitado</Button>
38
54
  <Button busy>Salvando…</Button>
39
- <Button icon={Plus}>Novo</Button>
40
- <Button icon={Plus} busy>Novo</Button>
55
+ <Button icon={<Plus />}>Novo</Button>
56
+ <Button icon={<Plus />} busy>Novo</Button>
41
57
  ```
42
58
 
43
59
  ## Como outro elemento (asChild)
@@ -57,10 +73,10 @@ buttonVariants serve para o caso sem filho único.
57
73
  |---|---|---|---|
58
74
  | `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação. |
59
75
  | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
60
- | `size` | `'default' \| 'sm' \| 'lg' \| 'icon' \| 'icon-sm' \| 'icon-xs'` | `'default'` | O tamanho. Os icon* são quadrados (2.25/2/1.5rem) para botões só de ícone, com `aria-label`. |
76
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | `'default'` | A medida na escala única dos controles (tabela acima). Os `icon-*` são quadrados para botões só de ícone, com `aria-label`. |
61
77
  | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
62
78
  | `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton em um nível de página). |
63
- | `icon` | `React.ElementType` | | Ícone à esquerda (ex.: icon={Plus}). No busy é trocado pelo Spinner — não soma. |
79
+ | `icon` | `React.ReactNode` | | Ícone à esquerda, como nó (ex.: `icon={<Plus />}`); o glifo segue o `size`. No busy é trocado pelo Spinner — não soma. |
64
80
 
65
81
  ## ButtonGroup
66
82
 
@@ -83,7 +99,7 @@ variações.
83
99
 
84
100
  ```tsx preview
85
101
  <ButtonGroup>
86
- <Button icon={Play}>Rodar agente developer</Button>
102
+ <Button icon={<Play />}>Rodar agente developer</Button>
87
103
  <ButtonGroupSeparator />
88
104
  <Button size="icon" aria-label="Mais opções">
89
105
  <ChevronDown />
@@ -102,7 +118,7 @@ semântica de outro elemento, como `label`.
102
118
  <GitBranch />
103
119
  empresa-x-api
104
120
  </ButtonGroupText>
105
- <Button variant="outline" icon={RotateCw}>Sincronizar</Button>
121
+ <Button variant="outline" icon={<RotateCw />}>Sincronizar</Button>
106
122
  </ButtonGroup>
107
123
  ```
108
124
 
@@ -1,3 +1,7 @@
1
+ O calendário fala pt-BR por padrão: nomes de mês e de dia vêm do `locale` (`ptBR` de
2
+ `date-fns/locale`) e os controles de navegação têm rótulos acessíveis em português. Passe outro
3
+ `locale` para trocar o idioma; `labels` sobrescreve rótulos individualmente.
4
+
1
5
  ## Dia único
2
6
 
3
7
  mode=single guarda uma Date — controle por selected/onSelect. defaultMonth abre o calendário no mês certo sem mexer na seleção.
@@ -60,3 +64,12 @@ captionLayout=dropdown troca o título do mês por seletores de mês e ano — b
60
64
  | `disabled` | `Matcher` | | Datas não selecionáveis — uma Date, um array, um { from, to } ou um predicado (date) => boolean. |
61
65
  | `buttonVariant` | `Button['variant']` | `'ghost'` | A variante dos botões de navegação (anterior/próximo). |
62
66
  | `showOutsideDays` | `boolean` | `true` | Mostra os dias do mês vizinho que completam a primeira e a última semana. |
67
+ | `locale` | `Locale` | `ptBR` | Idioma dos nomes de mês e de dia (um locale do date-fns). |
68
+ | `labels` | `Partial<Labels>` | rótulos em pt-BR | Rótulos acessíveis da navegação e dos seletores; mescla sobre o padrão. |
69
+
70
+ ## CalendarDayButton
71
+
72
+ Cada dia é um `CalendarDayButton` — um `Button` ghost quadrado que recebe os modificadores do
73
+ dia (`selected`, `range-start`, `today`…). Use `components={{ DayButton: … }}` para
74
+ decorar o dia (um marcador de evento, por exemplo) partindo dele em vez de reimplementar o
75
+ foco e a seleção.
@@ -47,3 +47,29 @@ Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog)
47
47
  </CardFooter>
48
48
  </Card>
49
49
  ```
50
+
51
+ ## Ação no cabeçalho
52
+
53
+ `CardAction` é o slot de ação do header (um botão ou menu). Quem compõe posiciona — em geral um
54
+ `CardHeader` em `flex-row` com o título de um lado e a ação do outro.
55
+
56
+ ```tsx preview col
57
+ <Card>
58
+ <CardHeader className="flex-row items-start justify-between">
59
+ <div>
60
+ <CardTitle>Empresa X</CardTitle>
61
+ <CardDescription>3 agentes vinculados.</CardDescription>
62
+ </div>
63
+ <CardAction>
64
+ <Button size="sm" variant="outline">Editar</Button>
65
+ </CardAction>
66
+ </CardHeader>
67
+ </Card>
68
+ ```
69
+
70
+ ## Propriedades de Card
71
+
72
+ | Propriedade | Tipo | Padrão | Descrição |
73
+ |---|---|---|---|
74
+ | `asChild` | `boolean` | `false` | Renderiza o filho com a superfície do Card (ex.: um `<button>` clicável inteiro). |
75
+ | `className` | `string` | | Compõe sobre a superfície; os slots (`CardHeader`, `CardBody`, `CardContent`, `CardFooter`, `CardAction`) são donos do próprio padding. |
@@ -91,3 +91,23 @@ continua valendo — é o caso degenerado do protocolo.
91
91
  Reidratação: passe `initialMessages` com o histórico persistido e troque a `key` do
92
92
  componente ao trocar de conversa. O rótulo do indicador é customizável por
93
93
  `humanizeTool={(name) => '…'}`.
94
+
95
+ ## Propriedades de Chat
96
+
97
+ | Propriedade | Tipo | Padrão | Descrição |
98
+ |---|---|---|---|
99
+ | `send` | `(messages: ChatMessage[]) => Promise<string> \| AsyncIterable<ChatEvent>` | | Modo autogerenciado: envia o histórico e devolve a resposta inteira ou um stream de eventos. Ignorado no modo controlado. |
100
+ | `messages` | `ChatTranscriptItem[]` | | Modo controlado: o transcript vem do app; com ele, `onSend`, `busy` e `activity` assumem. |
101
+ | `onSend` | `(text: string) => void \| boolean \| Promise<void \| boolean>` | | Modo controlado: recebe o texto enviado; retornar `false` devolve o texto ao composer. |
102
+ | `busy` | `boolean` | | Modo controlado: trava o composer enquanto o turno corre. |
103
+ | `activity` | `string \| null` | `undefined` | Indicador vivo: `null` mostra “Pensando…”, string mostra o rótulo; `undefined` esconde. |
104
+ | `notice` | `ReactNode` | | Aviso do app acima do composer (credencial, agente desatualizado…). |
105
+ | `composerActions` | `ReactNode` | | Seletores discretos na barra do composer (agente, app, escopo). |
106
+ | `composerClassName` | `string` | | Ajusta o contêiner externo do composer sem alcançar o DOM interno. |
107
+ | `greeting` | `string` | | Texto do estado vazio; some quando a conversa começa. |
108
+ | `empty` | `ReactNode` | | Estado vazio composto pelo app; vence `greeting` quando os dois existem. |
109
+ | `initialMessages` | `ChatMessage[]` | | Histórico inicial do modo autogerenciado; troque a `key` ao trocar de conversa. |
110
+ | `kickoff` | `() => Promise<string> \| AsyncIterable<ChatEvent>` | | Conversa que começa pelo assistente, uma vez, quando o transcript nasce vazio. |
111
+ | `renderArtifact` | `(artifact: ChatArtifact) => ReactNode` | link com o título | Render do evento `artifact`. |
112
+ | `humanizeTool` | `(name: string, detail?: string) => string` | pt-BR embutido | Rótulo humano do tool em uso no indicador vivo. |
113
+ | `placeholder` | `string` | `'Escreva uma mensagem…'` | Placeholder do composer. |
@@ -5,18 +5,39 @@ title: CLI opus
5
5
  # CLI opus
6
6
 
7
7
  O Opus traz um CLI que cobre o ciclo: faz o bootstrap, gera artefatos a partir das declarações,
8
- valida as convenções e expõe o estado vivo para os agentes via MCP.
8
+ valida as convenções e expõe o estado vivo para os agentes via MCP. `opus --help` lista os
9
+ comandos e `opus <comando> --help` detalha cada um.
9
10
 
10
11
  ## Gates
11
12
 
12
- > Use o check no CI e antes de entregar uma mudança. Ele informa quais contratos precisam de
13
- > ajuste e encerra com sucesso quando não encontra violações.
13
+ > Use os gates no CI e antes de entregar uma mudança. Cada um informa o que precisa de ajuste e
14
+ > encerra com sucesso (exit 0) quando não encontra violação.
14
15
 
15
16
  ```bash
16
- opus check src # valida as convenções das actions (exit ≠ 0 se violar)
17
- opus db check # drift entidade banco (read-only)
18
- opus db migrate # aplica o schema idempotente + drift-check na sequência
19
- opus seed check # valida bindings, dependências, ciclos e comandos paralelos
17
+ opus check src # convenções das actions e da UI (exit ≠ 0 se violar)
18
+ opus copy --check # inventário de copy ausente ou desatualizado
19
+ opus db check # drift entidade banco (read-only)
20
+ opus seed check # bindings, dependências, ciclos e scripts paralelos de seed
21
+ ```
22
+
23
+ `opus check` lê o source sem executar nada e aplica nove regras: cinco sobre as actions
24
+ (`action-name`, `kind`, `field-order`, `export`, `requires-sem-authorize`) e quatro sobre a UI
25
+ (`ui-structure`, `ui-semantic-api`, `removed-ui-token`, `unpaired-ui-surface`). Um projeto
26
+ marcado com `opus.json` e ainda sem actions passa vacuamente; sem o marcador, zero actions
27
+ falha, porque um gate vazio não é aprovação. `opus check --help` descreve cada regra.
28
+
29
+ ### Hook de pré-push
30
+
31
+ O hook Git que `opus setup` instala roda, antes de cada push: `opus copy --check`; depois
32
+ `opus pre-push materialization` na raiz, para confirmar que os artefatos Opus materializados
33
+ (skills, hooks, instruções) correspondem à versão adotada; e `opus check` em cada app com
34
+ `opus.json`. Qualquer um com exit ≠ 0 bloqueia o push. Os mesmos comandos podem ser executados à
35
+ mão para antecipar o resultado:
36
+
37
+ ```bash
38
+ opus pre-push # o mesmo opus check no diretório atual
39
+ opus pre-push apps/portal # o check de um app específico
40
+ opus pre-push materialization # só a freshness dos artefatos materializados
20
41
  ```
21
42
 
22
43
  ## Seeds de desenvolvimento e teste
@@ -31,9 +52,11 @@ opus seed apply customers.scenarios --profile smoke --scope local
31
52
  opus seed verify customers.scenarios --profile smoke --scope local
32
53
  ```
33
54
 
34
- `apply` converge quando repetido; não reset ou truncate no contrato. A skill
35
- `$create-opus-seed` estrutura um novo dataset, e `$apply-opus-seed` opera um seed registrado pela
36
- mesma CLI.
55
+ `--profile` escolhe o perfil (default: o `defaultProfile` do seed) e `--scope` declara o escopo
56
+ dos dados (a variável `OPUS_SEED_SCOPE` é a alternativa). `--json` devolve o resultado
57
+ estruturado, inclusive em caso de erro. `apply` converge quando repetido; não há reset ou
58
+ truncate no contrato. A skill `$create-opus-seed` estrutura um novo dataset, e
59
+ `$apply-opus-seed` opera um seed registrado pela mesma CLI.
37
60
 
38
61
  ## Geração e introspecção
39
62
 
@@ -41,23 +64,52 @@ mesma CLI.
41
64
  > é um lockfile versionado. A diferença do manifest torna a revisão objetiva.
42
65
 
43
66
  ```bash
44
- opus gen # manifest / openapi / docs / stubs a partir do opus.config.ts
45
- opus introspect # modelo da estrutura (actions/reactions/schedules + wiring)
67
+ opus gen # manifest / openapi / docs / stubs a partir do opus.config.ts
68
+ opus gen --config ./apps/api/opus.config.ts # config fora do diretório atual
69
+ opus gen --output ./custom/gen # pasta de saída (default: a do config, ou ./.gen)
70
+ opus copy # inventário semântico de copy dos contratos
71
+ opus introspect # modelo da estrutura (actions/reactions/schedules + wiring)
46
72
  opus introspect --json
47
73
  ```
48
74
 
49
- ## Bootstrap e templates
75
+ `opus copy` projeta os textos de `defineAction`/`defineContract` no inventário que a política de
76
+ copy da `@softize/base` valida. O caminho vem de `base.json` (`copy.inventory`; default
77
+ `.base/copy-inventory.json` na raiz Git), a escrita é atômica e o arquivo gerado deve ser
78
+ versionado. `--check` compara sem escrever e falha quando o inventário está ausente,
79
+ desatualizado ou contém copy dinâmica não declarada.
80
+
81
+ `--config` vale para `gen`, `db` e `seed` e sempre aponta para um caminho dentro do projeto. O
82
+ `gen` aceita `--force` por compatibilidade, mas a flag não altera nada: a saída mora em um
83
+ diretório dedicado e é sempre sobrescrita.
84
+
85
+ ## Banco
86
+
87
+ > Os comandos `db` carregam o `opus.config.ts` e abrem conexão; por isso rodam num runner isolado
88
+ > via `tsx`. O padrão é um schema idempotente: um script SQL evolutivo re-rodável, não migrations
89
+ > versionadas.
90
+
91
+ ```bash
92
+ opus db check # compara o schema do banco com as entidades (read-only)
93
+ opus db migrate # aplica o schema idempotente e roda o drift-check na sequência
94
+ opus db scaffold # rascunho kysely a partir do diff, como referência para escrever o SQL
95
+ ```
96
+
97
+ `db scaffold` gera um rascunho para revisão à mão; a verdade continua sendo o script. `db migrate
98
+ down` está aposentado e encerra com erro: sem histórico de migrations não há o que reverter —
99
+ rollback é editar o schema e rodar `opus db migrate` de novo. O `opus.config.ts` precisa expor a
100
+ factory lazy `database`, as entidades (ou domínios) e, opcionalmente, `schema` e `migrations`;
101
+ `opus db --help` detalha.
102
+
103
+ ## Bootstrap
50
104
 
51
105
  > `create` scaffolda um app novo com os pré-requisitos plugados; `setup` é per-app
52
- > (idempotente, nunca sobrescreve o seu); `add` copia um template do catálogo empacotado.
106
+ > (idempotente, nunca sobrescreve o seu).
53
107
 
54
108
  ```bash
55
- opus create meu-app # app canônico do zero: protocolo + UI + preview + automação
109
+ opus create meu-app # app canônico do zero: protocolo + UI + preview + automação
56
110
  opus create meu-cliente --monorepo # a RAIZ de um workspace (apps/* + packages/*)
57
- opus create apps/portal # dentro de um workspace: só o app (modo detectado)
58
- opus setup # grava opus.json e materializa a camada específica do SDK
59
- opus list # lista os templates disponíveis
60
- opus add action-form # copia um template do catálogo para o projeto
111
+ opus create apps/portal # dentro de um workspace: só o app (modo detectado)
112
+ opus setup # grava opus.json e materializa a camada específica do SDK
61
113
  ```
62
114
 
63
115
  O esqueleto do `create` versiona com o Opus (sai do mesmo pacote que o SDK que ele
@@ -50,6 +50,42 @@ frase. Não copie as regras da Base para cá.
50
50
  | placeholder de campo ou busca | `placeholder` |
51
51
  | `Select.emptyText` e grupos de opção | `empty-state` e `heading` |
52
52
  | confirmação local do `ActionTrigger` | `title`, `dialog-body` e `button` |
53
+ | `dialog.alert/confirm/prompt/choose` — `title`, `description`/`body`, `action`/`cancel`, `actions[].label` | `title`, `dialog-body`, `button` (e `placeholder` no `prompt`) |
54
+ | filhos de `TooltipContent` | `label` |
55
+ | `LabelHelp.help` | `helper-text` |
56
+ | `emptyMessage`, `errorMessage`, `retryLabel` de `DataState`, `PageState`, `ActionList`, `ActionListDialog` e `ActionView` | `empty-state`, `error`, `button` |
57
+
58
+ O tooltip entra como `label` porque nomeia um controle icon-only: é um fragmento curto, sem
59
+ ponto final, e a Base não define um papel próprio para tooltip. Texto de ajuda que precisa de
60
+ frase completa pertence ao `help` de um campo (contrato ou `LabelHelp`), não ao tooltip.
61
+
62
+ ## Alcance do inventário além das props
63
+
64
+ Quem vê o gate reprovar ou precisa de uma dispensa deve saber o que o extrator alcança sem
65
+ declaração adicional:
66
+
67
+ - **Diálogos imperativos.** `dialog.confirm({ title, description, action })` e as demais
68
+ respostas (`alert`, `prompt`, `choose`) entram no inventário como se fossem props de um
69
+ `ActionFormDialog`; o campo do diagnóstico é `dialog.confirm().title`,
70
+ `dialog.choose().actions[0].label` etc. Constantes locais resolvem normalmente. Uma função
71
+ que devolve template (`description: describe(nome)`) gera o diagnóstico `content` habitual e
72
+ se declara em `copy.dynamic` como `message-template`. Opções construídas em tempo de execução
73
+ ou mutadas depois de declaradas reprovam como estrutura, porque nenhum texto pode ser
74
+ atribuído a elas.
75
+ - **`LabelHelp` como filho.** `<FieldLabel>Nome<LabelHelp help="…" /></FieldLabel>` inventaria
76
+ `Nome` como label e a ajuda como helper-text; o ícone não torna o label opaco. Um wrapper
77
+ local com o mesmo nome continua opaco, porque o extrator não infere o que ele renderiza.
78
+ - **Rótulos em array literal local.** Quando um componente mapeado lê `item.label` (ou a chave
79
+ destruturada) dentro de `map`, `forEach`, `filter` ou `for…of` sobre um array literal do
80
+ mesmo arquivo, cada literal do array vira um texto na linha em que foi escrito, em vez de um
81
+ diagnóstico sobre a prop. `filter`, `slice`, `toSorted` e `toReversed` podem ficar entre o
82
+ array e a iteração. O limite é deliberado: o array precisa ser literal e declarado no mesmo
83
+ arquivo; o elemento só pode ser lido (`item.chave`), nunca passado adiante, espalhado ou
84
+ atribuído; o callback não pode receber o próprio array como terceiro parâmetro; e nenhum
85
+ elemento pode ter a chave dinâmica. Arrays importados, derivados por spread ou por
86
+ concatenação continuam gerando o diagnóstico da prop.
87
+ - **Elementos JSX genéricos.** `<ActionList<Input, Row> emptyMessage="…">` extrai igual a
88
+ `<ActionList emptyMessage="…">`.
53
89
 
54
90
  Copy visual e nome acessível são superfícies cumulativas. Um `aria-label` estático nomeia
55
91
  um controle icon-only, mas não torna aceitável nem invisível ao gate um texto visual opaco.
@@ -48,3 +48,18 @@ render(
48
48
  />,
49
49
  )
50
50
  ```
51
+
52
+ ## Propriedades de Composer
53
+
54
+ | Propriedade | Tipo | Padrão | Descrição |
55
+ |---|---|---|---|
56
+ | `value` | `string` | | Texto controlado; o dono do estado é quem compõe. |
57
+ | `onChange` | `(value: string) => void` | | Recebe cada alteração do texto. |
58
+ | `onSubmit` | `() => void` | | Enter (sem Shift) ou o botão enviar; só dispara quando dá para enviar. |
59
+ | `onHistoryPrevious` / `onHistoryNext` | `() => boolean` | | Navegação por ↑/↓ no histórico do dono; retorne `true` quando a tecla foi consumida. |
60
+ | `busy` | `boolean` | `false` | Trava o composer enquanto o turno corre; o enviar vira spinner. |
61
+ | `submitDisabled` | `boolean` | `false` | Gate extra de envio além de vazio e `busy` (ex.: falta escolher o app). |
62
+ | `placeholder` | `string` | `'Escreva uma mensagem…'` | Texto de orientação do campo. |
63
+ | `rows` | `number` | `1` | Linhas iniciais do textarea; ele cresce com o conteúdo. |
64
+ | `autoFocus` | `boolean` | | Foca o campo ao montar. |
65
+ | `actions` | `ReactNode` | | Controles discretos à esquerda do enviar; presente, o composer vira duas linhas. |
@@ -22,7 +22,8 @@ render(
22
22
 
23
23
  Use os slots quando o header precisar de composição própria. A árvore aceita exatamente um
24
24
  `ContentHeader` e um `ContentBody` como filhos diretos. O header exige um `ContentTitle` e aceita
25
- uma descrição, um metadado e uma região de ações.
25
+ uma descrição, um contador (`ContentMeta`) e uma região de ações — a mesma anatomia de `PageHeader`,
26
+ com os mesmos slots e o mesmo layout; só o nível do heading e a hierarquia visual mudam.
26
27
 
27
28
  ```tsx preview col
28
29
  render(
@@ -42,3 +43,18 @@ render(
42
43
 
43
44
  As duas formas geram os mesmos elementos, estilos e `data-slot`. `opus check` reprova slots fora
44
45
  do pai correto, filhos estruturais indiretos e a mistura de shorthand com composição explícita.
46
+
47
+ ## Propriedades de Content
48
+
49
+ | Propriedade | Tipo | Padrão | Descrição |
50
+ |---|---|---|---|
51
+ | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
52
+ | `count` | `number` | | Forma curta: total de itens ao lado do título — o mesmo `count` de `Page`. |
53
+ | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
54
+ | `actions` | `ReactNode` | | Forma curta: ações alinhadas à direita do header. |
55
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | herdado | Nível semântico do heading, independente do destaque visual. |
56
+ | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
57
+
58
+ Na composição explícita, `ContentHeader` recebe `ContentTitle`, `ContentMeta`, `ContentDescription` e
59
+ `ContentActions`, e `ContentBody` recebe o conteúdo; nenhum desses slots aceita `title` ou `level`
60
+ próprios — a hierarquia é declarada em `Content`. `ContentHeader` não existe fora de `Content`.
@@ -29,3 +29,11 @@ Com filhos, o valor visível fica à esquerda e o ícone à direita — clicar n
29
29
  copiar (3s)
30
30
  </Copyable>
31
31
  ```
32
+
33
+ ## Propriedades de Copyable
34
+
35
+ | Propriedade | Tipo | Padrão | Descrição |
36
+ |---|---|---|---|
37
+ | `value` | `string` | | O texto que vai para a área de transferência no clique. |
38
+ | `feedbackMs` | `number` | `1500` | Duração do estado “copiado”, em milissegundos. |
39
+ | `children` | `ReactNode` | | Rótulo ao lado do ícone; sem ele, o controle é só o ícone com nome acessível. |
@@ -1,19 +1,21 @@
1
1
  ## Estados
2
2
 
3
- Use `DataState` para apresentar carregamento, erro, vazio e conteúdo de uma mesma consulta. O
4
- carregamento usa `Spinner`; o vazio preserva uma moldura sólida; e o erro apresenta uma mensagem
5
- segura, sem expor detalhes técnicos. Para uma ação em andamento depois do clique, use `busy` em
6
- `Button`.
3
+ Use `DataState` para apresentar carregamento, erro, vazio e conteúdo de uma mesma consulta. As
4
+ superfícies são as mesmas de `PageState`, na escala de uma seção: o carregamento é um contêiner
5
+ `role="status"` com o `Spinner`; o vazio compõe `Empty` com moldura sólida e `emptyMessage` como
6
+ título; o erro é um `Alert` de contexto `danger` com uma mensagem segura, sem expor detalhes
7
+ técnicos, e o botão de recuperação quando há `onRetry`. Para uma ação em andamento depois do
8
+ clique, use `busy` em `Button`.
7
9
 
8
10
  ```tsx preview col
9
11
  <div className="w-full space-y-3">
10
12
  <DataState loading>
11
13
  <div />
12
14
  </DataState>
13
- <DataState empty emptyText="Nenhum papel.">
15
+ <DataState empty emptyMessage="Nenhum papel.">
14
16
  <div />
15
17
  </DataState>
16
- <DataState error={{ message: 'detalhe técnico fica no console' }}>
18
+ <DataState error={{ message: 'detalhe técnico fica no console' }} onRetry={() => undefined}>
17
19
  <div />
18
20
  </DataState>
19
21
  </div>
@@ -22,13 +24,13 @@ segura, sem expor detalhes técnicos. Para uma ação em andamento depois do cli
22
24
  ## Dentro de uma tabela
23
25
 
24
26
  Em uma tabela já emoldurada, passe `colSpan` para ocupar uma linha inteira dentro de `<tbody>`. A
25
- tabela continua responsável pela borda, evitando uma segunda moldura no estado vazio. Para uma
26
- região disponível para criação ou vínculo, use `Empty`.
27
+ tabela continua responsável pela borda: o `Empty` dentro dela vem sem moldura. Para uma região
28
+ disponível para criação ou vínculo, use `Empty` diretamente, com a moldura tracejada.
27
29
 
28
30
  ```tsx preview col
29
31
  <table className="w-full overflow-hidden rounded-lg border border-border text-sm">
30
32
  <tbody>
31
- <DataState empty emptyText="Nenhum usuário." colSpan={3}>
33
+ <DataState empty emptyMessage="Nenhum usuário." colSpan={3}>
32
34
  <tr>
33
35
  <td />
34
36
  </tr>
@@ -42,8 +44,10 @@ região disponível para criação ou vínculo, use `Empty`.
42
44
  | Propriedade | Tipo | Padrão | Descrição |
43
45
  |---|---|---|---|
44
46
  | `loading` | `boolean` | | Carregando (antes do conteúdo) — mostra o Spinner centralizado. |
45
- | `empty` | `boolean` | | Sem itens — mostra o emptyText. |
46
- | `emptyText` | `string` | | Texto do vazio (pt-BR, ex.: "Nenhum papel."). |
47
- | `error` | `{ message?: string } \| null` | | Erro da carga — aviso calmo. A mensagem técnica não vai para tela (use errorText). |
48
- | `errorText` | `string` | `'Não foi possível carregar.'` | Aviso de erro, orientado ao usuário. |
47
+ | `empty` | `boolean` | | Sem itens — compõe `Empty` com o `emptyMessage`. |
48
+ | `emptyMessage` | `string` | `'Nada por aqui.'` | Frase do vazio (ex.: "Nenhum papel."). |
49
+ | `error` | `{ message?: string } \| null` | | Erro da carga — aviso calmo. A mensagem técnica não vai para tela (use `errorMessage`). |
50
+ | `errorMessage` | `string` | `'Não foi possível carregar.'` | Título do aviso de erro, orientado à pessoa. |
51
+ | `onRetry` | `() => void \| Promise<void>` | | Recuperação: mostra o botão de tentar de novo no estado de erro. |
52
+ | `retryLabel` | `string` | `'Tentar de novo'` | Rótulo do botão de recuperação. |
49
53
  | `colSpan` | `number` | | Em tabela: renderiza o estado como `<tr><td colSpan>` (cabe direto no tbody). |
@@ -9,7 +9,7 @@ validação, use `Field`.
9
9
  label="Estágio"
10
10
  value={
11
11
  <DictionaryValue
12
- dict={{ keys: ['prospect', 'customer'], entries: { prospect: { label: 'Prospect' }, customer: { label: 'Cliente', context: 'success' } }, presentation: 'stage' }}
12
+ dict={{ keys: ['prospect', 'customer'], entries: { prospect: { label: 'Prospecto' }, customer: { label: 'Cliente', context: 'success' } }, presentation: 'stage' }}
13
13
  value="prospect"
14
14
  />
15
15
  }
@@ -56,3 +56,21 @@ mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
56
56
  />
57
57
  </DetailGroup>
58
58
  ```
59
+
60
+ ## Propriedades de DetailGroup
61
+
62
+ | Propriedade | Tipo | Padrão | Descrição |
63
+ |---|---|---|---|
64
+ | `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica a superfície e a moldura canônicas ao conjunto. |
65
+ | `dividers` | `boolean` | `false` | Hairlines somente entre os campos, sem exigir moldura externa. |
66
+ | `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Colunas responsivas ou distribuição automática por largura mínima. |
67
+ | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
68
+
69
+ ## Propriedades de DetailField
70
+
71
+ | Propriedade | Tipo | Padrão | Descrição |
72
+ |---|---|---|---|
73
+ | `label` | `ReactNode` | | A chave do par. |
74
+ | `value` | `ReactNode` | | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
75
+ | `icon` | `ReactNode` | | Ícone decorativo antes do par chave/valor. |
76
+ | `empty` | `ReactNode` | `“Não informado”` | O que a ausência significa neste campo: um rótulo ou um nó próprio. |
@@ -305,7 +305,7 @@ avançada; ele recebe `children` e `container` conforme o portal do Radix.
305
305
  ## Propriedades de DialogHost
306
306
 
307
307
  `DialogHost` não recebe propriedades. Monte uma instância no shell para atender toda a API
308
- imperativa. `ConfirmHost` permanece como alias de migração.
308
+ imperativa.
309
309
 
310
310
  ## Opções de dialog.alert
311
311
 
@@ -363,6 +363,3 @@ imperativa. `ConfirmHost` permanece como alias de migração.
363
363
  | `context` | `ButtonContext` | Última ação: `primary`; demais: `neutral` | Define o significado semântico. |
364
364
  | `variant` | `ButtonVariant` | Última ação: `solid`; demais: `ghost` | Define o tratamento visual. |
365
365
  | `disabled` | `boolean` | `false` | Impede a escolha desta ação. |
366
-
367
- `confirm()` e `ConfirmHost` continuam disponíveis apenas como aliases de migração para
368
- `dialog.confirm()` e `DialogHost`.
@@ -8,7 +8,7 @@ sem perder o rótulo visível.
8
8
  value="pj"
9
9
  />
10
10
  <DictionaryValue
11
- dict={{ keys: ['prospect', 'customer'], entries: { prospect: { label: 'Prospect' }, customer: { label: 'Cliente', context: 'success' } }, presentation: 'stage' }}
11
+ dict={{ keys: ['prospect', 'customer'], entries: { prospect: { label: 'Prospecto' }, customer: { label: 'Cliente', context: 'success' } }, presentation: 'stage' }}
12
12
  value="customer"
13
13
  />
14
14
  <DictionaryValue
@@ -37,7 +37,7 @@ export const customerKindDict = t.dict(
37
37
 
38
38
  export const customerStageDict = t.dict(
39
39
  {
40
- prospect: { label: 'Prospect', description: 'Relacionamento ainda em prospecção.' },
40
+ prospect: { label: 'Prospecto', description: 'Relacionamento ainda em prospecção.' },
41
41
  customer: { label: 'Cliente', context: 'success' },
42
42
  },
43
43
  { doc: 'Estágio comercial atual da parte.', presentation: 'stage' },
@@ -106,6 +106,13 @@ dicionário registrado no provider: `{ key: 'source', label: 'Fonte', dictionary
106
106
  Dimensões independentes (tipo e estágio, por exemplo) ficam em colunas distintas; não empilhar
107
107
  uma sob a outra como texto secundário.
108
108
 
109
+ ## useDicts
110
+
111
+ `useDicts()` devolve os dicionários registrados em `OpusProvider` (`dicts`), chaveados pela `ref`.
112
+ É o que `ActionList`, `ActionForm` e `DictionaryValue` consultam para resolver
113
+ `options: { kind: 'dictionary', ref }` e colunas nomeadas por `dictionary`; fora do provider, o
114
+ resultado é vazio e a resolução cai na meta do `t.dict` que viaja no schema.
115
+
109
116
  ## Propriedades de DictionaryValue
110
117
 
111
118
  | Propriedade | Tipo | Padrão | Descrição |
@@ -67,3 +67,11 @@ já monta.
67
67
  | --- | --- | --- | --- |
68
68
  | `position` | `'bottom' \| 'bottom-left' \| 'bottom-right'` | `'bottom'` | Aresta do contêiner onde a barra se ancora. |
69
69
  | `label` | `string` | | Nome acessível da barra. |
70
+
71
+ ## Propriedades de SurfaceStatus
72
+
73
+ | Propriedade | Tipo | Padrão | Descrição |
74
+ | --- | --- | --- | --- |
75
+ | `position` | `'top-right' \| 'top-left'` | `'top-right'` | Canto da superfície onde o estado se ancora. |
76
+ | `context` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O que o estado comunica; tinge borda e texto pela família semântica. |
77
+ | `actions` | `ReactNode` | | Ações do recurso aberto, fora da região viva. |
@@ -15,3 +15,11 @@ acessível. Sem `label`, o ponto é decorativo.
15
15
  ```
16
16
 
17
17
  Use `Badge` quando o estado precisar permanecer legível sem depender do contexto ao redor.
18
+
19
+ ## Propriedades de Dot
20
+
21
+ | Propriedade | Tipo | Padrão | Descrição |
22
+ |---|---|---|---|
23
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O significado da cor. |
24
+ | `variant` | `'solid' \| 'outline'` | `'solid'` | Ponto preenchido ou só contornado. |
25
+ | `label` | `string` | | Nome acessível quando a cor comunica estado; sem ele o ponto é decorativo (`aria-hidden`). |
@@ -53,8 +53,8 @@ título e descrição agrupados no centro.
53
53
 
54
54
  ## Mídia sem moldura
55
55
 
56
- `EmptyMedia variant="default"` não desenha fundo. Use essa variação para ilustrações ou mídias que
57
- tenham presença visual própria.
56
+ `EmptyMedia` sem `variant` (o padrão, `default`) não desenha fundo. Use essa forma para ilustrações
57
+ ou mídias que tenham presença visual própria.
58
58
 
59
59
  ```tsx preview col
60
60
  <Empty>
@@ -1,8 +1,8 @@
1
1
  ---
2
- title: Getting started
2
+ title: Primeiros passos
3
3
  ---
4
4
 
5
- # Getting started
5
+ # Primeiros passos
6
6
 
7
7
  O Opus ajuda cliente e servidor a preservar as mesmas regras à medida que uma aplicação
8
8
  evolui. Entidades e contratos de action ficam em uma camada compartilhada; o runtime, a UI e