@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
@@ -7,7 +7,7 @@ title: Autenticação
7
7
  Quem é o usuário, de qual tenant, e o que ele pode. O contrato é um adapter do core
8
8
  (`AuthAdapter`): a cada request o runtime chama `resolveContext` e injeta o resultado no
9
9
  handler — `ctx.user`, `ctx.tenantId`, `ctx.can`. O Opus **não** implementa RBAC/ABAC; ele
10
- delega a decisão pro `can` que o driver pluga.
10
+ delega a decisão para o `can` que o driver pluga.
11
11
 
12
12
  ## O contrato
13
13
 
@@ -31,7 +31,7 @@ política usada por ela.
31
31
  import { jwtAuth } from '@softize/opus/auth/jwt'
32
32
  import { betterAuthSession } from '@softize/opus/auth/better-auth'
33
33
 
34
- // JWT: valida o token (HS256 por padrão) e mapeia o payload pro User.
34
+ // JWT: valida o token (HS256 por padrão) e mapeia o payload para o User.
35
35
  const jwt = jwtAuth({ secret: process.env.JWT_SECRET! })
36
36
 
37
37
  // better-auth: valida a sessão contra um IdP better-auth remoto.
@@ -44,7 +44,7 @@ const idp = betterAuthSession({
44
44
 
45
45
  O `jwt` procura o token no `Authorization: Bearer`, em cookie ou custom (via `getToken`); o
46
46
  `secret` pode ser string ou um resolver async por `kid`. O `betterAuthSession` faz fetch da
47
- sessão no IdP (`timeoutMs`, default 5s) e mapeia pro `User`/tenant/can (o `can` default nega
47
+ sessão no IdP (`timeoutMs`, default 5s) e mapeia para o `User`/tenant/can (o `can` default nega
48
48
  tudo — plugue o seu).
49
49
 
50
50
  ## No runtime
@@ -1,4 +1,4 @@
1
- ## Básico
1
+ ## Retrato com imagem
2
2
 
3
3
  AvatarImage com src/alt e AvatarFallback com as iniciais — o fallback aparece enquanto a imagem
4
4
  carrega ou se ela falha.
@@ -12,8 +12,8 @@ carrega ou se ela falha.
12
12
 
13
13
  ## Fallback de iniciais
14
14
 
15
- Sem AvatarImage (ou com src quebrado), só o AvatarFallback renderiza — iniciais pra pessoa, ícone
16
- pra agente.
15
+ Sem AvatarImage (ou com src quebrado), só o AvatarFallback renderiza — iniciais para pessoa, ícone
16
+ para agente.
17
17
 
18
18
  ```tsx preview
19
19
  <Avatar>
@@ -28,7 +28,7 @@ pra agente.
28
28
 
29
29
  ## Tamanhos
30
30
 
31
- size sm/default/lg — o fallback acompanha o tamanho. sm pra listas densas, lg pra cabeçalho de
31
+ size sm/default/lg — o fallback acompanha o tamanho. sm para listas densas, lg para cabeçalho de
32
32
  workspace.
33
33
 
34
34
  ```tsx preview
@@ -45,8 +45,8 @@ workspace.
45
45
 
46
46
  ## Com selo de status
47
47
 
48
- AvatarBadge é o ponto no canto inferior — verde pro agente developer rodando uma sessão, cinza
49
- pro ocioso. Tinja com className.
48
+ AvatarBadge é o ponto no canto inferior — verde para o agente developer rodando uma sessão, cinza
49
+ para o ocioso. Tinja com className.
50
50
 
51
51
  ```tsx preview
52
52
  <Avatar>
@@ -82,13 +82,33 @@ excedente — os membros do workspace Empresa X.
82
82
  </AvatarGroup>
83
83
  ```
84
84
 
85
- ## Props
85
+ ## Propriedades de Avatar
86
86
 
87
- | Prop | Tipo | Default | Descrição |
87
+ | Propriedade | Tipo | Padrão | Descrição |
88
88
  |---|---|---|---|
89
- | `size` (Avatar) | `'sm' \| 'default' \| 'lg'` | `'default'` | Diâmetro do retrato o fallback e o selo acompanham. |
90
- | `src` (AvatarImage) | `string` | | URL da imagem. Enquanto carrega (ou se falha), o AvatarFallback fica no lugar. |
91
- | `alt` (AvatarImage) | `string` | | Texto alternativo da imagem — o nome da pessoa ou do agente. |
92
- | `children` (AvatarFallback) | `React.ReactNode` | | O que aparece sem imagem: iniciais (pessoa) ou ícone (agente). |
93
- | `className` (AvatarBadge) | `string` | | Selo no canto inferior — tinja o fundo (ex.: bg-emerald-500) pra refletir o status. |
94
- | `children` (AvatarGroupCount) | `React.ReactNode` | | O excedente da pilha (ex.: "+3"), fechando o AvatarGroup. |
89
+ | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Diâmetro do retrato; o fallback e o selo acompanham a escala. |
90
+
91
+ ## Propriedades de AvatarImage
92
+
93
+ | Propriedade | Tipo | Padrão | Descrição |
94
+ |---|---|---|---|
95
+ | `src` | `string` | | URL da imagem. Enquanto ela carrega ou quando falha, `AvatarFallback` ocupa o lugar. |
96
+ | `alt` | `string` | | Texto alternativo que identifica a pessoa ou o agente. |
97
+
98
+ ## Propriedades de AvatarFallback
99
+
100
+ | Propriedade | Tipo | Padrão | Descrição |
101
+ |---|---|---|---|
102
+ | `children` | `React.ReactNode` | | Iniciais ou ícone exibido quando a imagem não está disponível. |
103
+
104
+ ## Propriedades de AvatarBadge
105
+
106
+ | Propriedade | Tipo | Padrão | Descrição |
107
+ |---|---|---|---|
108
+ | `className` | `string` | | Classes usadas para comunicar visualmente o status no selo. |
109
+
110
+ ## Propriedades de AvatarGroupCount
111
+
112
+ | Propriedade | Tipo | Padrão | Descrição |
113
+ |---|---|---|---|
114
+ | `children` | `React.ReactNode` | | Quantidade excedente no fim do grupo, como `+3`. |
@@ -1,35 +1,33 @@
1
- ## Intenção
1
+ ## Contexto e variante
2
2
 
3
- As quatro variantes do shadcn: categoria, papel, alerta. Badge é não-interativo — pra clique, use
4
- Button.
3
+ Badge é não-interativo — para clique, use Button. `context` comunica o significado; `variant`
4
+ escolhe entre preenchimento sólido, superfície sutil ou contorno.
5
5
 
6
6
  ```tsx preview
7
- <Badge>Agente</Badge>
8
- <Badge variant="secondary">Skill</Badge>
9
- <Badge variant="outline">Monorepo</Badge>
10
- <Badge variant="destructive">Arquivado</Badge>
7
+ <Badge context="neutral">Agente</Badge>
8
+ <Badge context="neutral" variant="outline">Monorepo</Badge>
9
+ <Badge context="danger" variant="solid">Arquivado</Badge>
11
10
  ```
12
11
 
13
- ## Tons de status da casa
12
+ ## Contextos de status
14
13
 
15
- success/warning/info/danger (fill tingido + borda translúcida) convenção da casa pra estado
16
- semântico, igual ao KindBadge do Maestro. Não-interativos. `danger` é o tom tonal da família;
17
- `destructive` continua sólido, pra alerta e ação. Valor de dicionário com papel declarado usa
18
- `DictionaryValue`, que escolhe o tom pela metadata em vez de repetir esta escolha em cada tela.
14
+ `success`, `warning`, `info` e `danger` usam `subtle` por padrão. Valor de dicionário com papel
15
+ declarado usa `DictionaryValue`, que escolhe o contexto pela metadata em vez de repetir esta
16
+ decisão em cada tela.
19
17
 
20
18
  ```tsx preview
21
- <Badge variant="success">Ativa</Badge>
22
- <Badge variant="warning">Aguardando revisor</Badge>
23
- <Badge variant="info">Em sessão</Badge>
24
- <Badge variant="danger">Bloqueada</Badge>
19
+ <Badge context="success">Ativa</Badge>
20
+ <Badge context="warning">Aguardando revisor</Badge>
21
+ <Badge context="info">Em sessão</Badge>
22
+ <Badge context="danger">Bloqueada</Badge>
25
23
  ```
26
24
 
27
25
  ## Com ícone
28
26
 
29
- Um svg filho ganha size-3 automaticamente — bom pra reforçar o estado sem crescer o rótulo.
27
+ Um svg filho ganha size-3 automaticamente — bom para reforçar o estado sem crescer o rótulo.
30
28
 
31
29
  ```tsx preview
32
- <Badge variant="success"><CircleCheck /> Regressão verde</Badge>
30
+ <Badge context="success"><CircleCheck /> Regressão verde</Badge>
33
31
  ```
34
32
 
35
33
  ## Como link (asChild)
@@ -38,14 +36,15 @@ asChild renderiza o filho (Radix Slot) — um `<a>` com cara de badge, com hover
38
36
  variantes.
39
37
 
40
38
  ```tsx preview
41
- <Badge asChild variant="secondary">
39
+ <Badge asChild context="neutral" variant="solid">
42
40
  <a href="#" onClick={(e) => e.preventDefault()}>Empresa X</a>
43
41
  </Badge>
44
42
  ```
45
43
 
46
- ## Props
44
+ ## Propriedades de Badge
47
45
 
48
- | Prop | Tipo | Default | Descrição |
46
+ | Propriedade | Tipo | Padrão | Descrição |
49
47
  |---|---|---|---|
50
- | `variant` | `'default' \| 'secondary' \| 'destructive' \| 'outline' \| 'success' \| 'warning' \| 'info' \| 'danger'` | `'default'` | Intenção (default/secondary/destructive/outline) ou tom de status da casa (success/warning/info/danger). |
48
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O significado ou destaque contextual. |
49
+ | `variant` | `'solid' \| 'subtle' \| 'outline'` | `'subtle'` | O tratamento visual aplicado ao contexto. |
51
50
  | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<span>` — ex.: um `<a>` com cara de badge. |
@@ -1,4 +1,4 @@
1
- ## Básico
1
+ ## Caminho atual
2
2
 
3
3
  A composição é manual: BreadcrumbLink nos níveis navegáveis, BreadcrumbPage no atual (não
4
4
  clicável, aria-current=page) e um BreadcrumbSeparator entre cada item.
@@ -23,7 +23,7 @@ clicável, aria-current=page) e um BreadcrumbSeparator entre cada item.
23
23
 
24
24
  ## Com ícone e separador custom
25
25
 
26
- O primeiro nível pode levar um ícone do lucide. BreadcrumbSeparator aceita children pra trocar o
26
+ O primeiro nível pode levar um ícone do lucide. BreadcrumbSeparator aceita children para trocar o
27
27
  chevron padrão por outro glifo (aqui, uma barra).
28
28
 
29
29
  ```tsx preview col-start
@@ -53,7 +53,7 @@ chevron padrão por outro glifo (aqui, uma barra).
53
53
 
54
54
  ## Colapsado
55
55
 
56
- Trilha funda demais pro espaço: BreadcrumbEllipsis substitui os níveis do meio (que viram um
56
+ Trilha funda demais para o espaço: BreadcrumbEllipsis substitui os níveis do meio (que viram um
57
57
  menu/popover) e mantém só a raiz e o destino.
58
58
 
59
59
  ```tsx preview col-start
@@ -78,10 +78,15 @@ menu/popover) e mantém só a raiz e o destino.
78
78
  </Breadcrumb>
79
79
  ```
80
80
 
81
- ## Props
81
+ ## Propriedades de BreadcrumbLink
82
82
 
83
- | Prop | Tipo | Default | Descrição |
83
+ | Propriedade | Tipo | Padrão | Descrição |
84
84
  |---|---|---|---|
85
- | `asChild` (BreadcrumbLink) | `boolean` | `false` | Funde as props no filho (via Slot) — use pra integrar o Link do seu roteador no lugar do `<a>` nativo. |
86
- | `href` (BreadcrumbLink) | `string` | | Destino do nível navegável — o que o consumidor decide por item. |
87
- | `children` (BreadcrumbSeparator) | `React.ReactNode` | `<ChevronRight />` | Glifo entre os itens. Omita pro chevron padrão ou passe outro ícone. |
85
+ | `asChild` | `boolean` | `false` | Repassa as propriedades ao filho para integrar o link do roteador no lugar de `<a>`. |
86
+ | `href` | `string` | | Destino do nível navegável. |
87
+
88
+ ## Propriedades de BreadcrumbSeparator
89
+
90
+ | Propriedade | Tipo | Padrão | Descrição |
91
+ |---|---|---|---|
92
+ | `children` | `React.ReactNode` | `<ChevronRight />` | Elemento entre os itens. Omita para usar o chevron padrão ou passe outro ícone. |
@@ -1,15 +1,17 @@
1
- ## Variantes
1
+ ## Contexto e variante
2
2
 
3
- variant é intenção, não decoração: default pra ação principal (uma por tela), destructive
4
- quando destrói de verdade.
3
+ `context` declara a hierarquia ou o risco da ação; `variant` escolhe o tratamento visual. Use
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
7
 
6
8
  ```tsx preview
7
9
  <Button>Criar workspace</Button>
8
- <Button variant="secondary">Duplicar</Button>
9
- <Button variant="outline">Ver prévia</Button>
10
- <Button variant="ghost">Cancelar</Button>
11
- <Button variant="destructive">Excluir</Button>
12
- <Button variant="link">Ver documentação</Button>
10
+ <Button context="neutral" variant="solid">Duplicar</Button>
11
+ <Button context="neutral" variant="outline">Ver prévia</Button>
12
+ <Button context="neutral" variant="ghost">Cancelar</Button>
13
+ <Button context="danger" variant="solid">Excluir</Button>
14
+ <Button context="primary" variant="link">Ver documentação</Button>
13
15
  ```
14
16
 
15
17
  ## Tamanhos
@@ -29,7 +31,7 @@ O tamanho icon exige `aria-label`, porque não há texto visível. Os botões s
29
31
 
30
32
  busy = ação em andamento (DEPOIS do clique): o Spinner e o disabled vêm do botão. Com icon, o
31
33
  Spinner TROCA o ícone (não soma). Não confunda com carregar conteúdo (ANTES) — isso é Spinner
32
- centralizado/Skeleton num nível de página.
34
+ centralizado/Skeleton em um nível de página.
33
35
 
34
36
  ```tsx preview
35
37
  <Button disabled>Desabilitado</Button>
@@ -41,7 +43,7 @@ centralizado/Skeleton num nível de página.
41
43
  ## Como outro elemento (asChild)
42
44
 
43
45
  Âncora com cara de botão: asChild renderiza o filho (Radix Slot) — sem forkar estilo.
44
- buttonVariants serve pro caso sem filho único.
46
+ buttonVariants serve para o caso sem filho único.
45
47
 
46
48
  ```tsx preview
47
49
  <Button asChild variant="outline">
@@ -49,12 +51,88 @@ buttonVariants serve pro caso sem filho único.
49
51
  </Button>
50
52
  ```
51
53
 
52
- ## Props
54
+ ## Propriedades de Button
53
55
 
54
- | Prop | Tipo | Default | Descrição |
56
+ | Propriedade | Tipo | Padrão | Descrição |
55
57
  |---|---|---|---|
56
- | `variant` | `'default' \| 'secondary' \| 'outline' \| 'ghost' \| 'destructive' \| 'link'` | `'default'` | A intenção da ação define cor e peso visual. |
58
+ | `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação. |
59
+ | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
57
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`. |
58
- | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — pra âncoras e afins. |
59
- | `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton num nível de página). |
61
+ | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
62
+ | `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). |
60
63
  | `icon` | `React.ElementType` | | Ícone à esquerda (ex.: icon={Plus}). No busy é trocado pelo Spinner — não soma. |
64
+
65
+ ## ButtonGroup
66
+
67
+ Use `ButtonGroup` quando ações relacionadas precisarem formar um bloco contínuo. As bordas internas
68
+ colapsam e somente as pontas externas permanecem arredondadas. Mantenha a mesma variante nos filhos
69
+ para preservar a unidade visual.
70
+
71
+ ```tsx preview
72
+ <ButtonGroup>
73
+ <Button variant="outline">Visão geral</Button>
74
+ <Button variant="outline">Sessões</Button>
75
+ <Button variant="outline">Habilidades</Button>
76
+ </ButtonGroup>
77
+ ```
78
+
79
+ ### Ação dividida
80
+
81
+ Combine a ação principal, um separador e um botão de ícone quando o mesmo comando oferecer
82
+ variações.
83
+
84
+ ```tsx preview
85
+ <ButtonGroup>
86
+ <Button icon={Play}>Rodar agente developer</Button>
87
+ <ButtonGroupSeparator />
88
+ <Button size="icon" aria-label="Mais opções">
89
+ <ChevronDown />
90
+ </Button>
91
+ </ButtonGroup>
92
+ ```
93
+
94
+ ### Com rótulo
95
+
96
+ `ButtonGroupText` adiciona um contexto inerte ao grupo. Ele também aceita `asChild` para assumir a
97
+ semântica de outro elemento, como `label`.
98
+
99
+ ```tsx preview
100
+ <ButtonGroup>
101
+ <ButtonGroupText>
102
+ <GitBranch />
103
+ empresa-x-api
104
+ </ButtonGroupText>
105
+ <Button variant="outline" icon={RotateCw}>Sincronizar</Button>
106
+ </ButtonGroup>
107
+ ```
108
+
109
+ ### Vertical
110
+
111
+ `orientation="vertical"` empilha os filhos e transfere a junção das bordas para o eixo vertical.
112
+
113
+ ```tsx preview col-start
114
+ <ButtonGroup orientation="vertical">
115
+ <Button variant="outline" size="icon" aria-label="Rodar sessão"><Play /></Button>
116
+ <Button variant="outline" size="icon" aria-label="Pausar sessão"><Pause /></Button>
117
+ <Button variant="outline" size="icon" aria-label="Reiniciar sessão"><RotateCw /></Button>
118
+ </ButtonGroup>
119
+ ```
120
+
121
+ ### Propriedades de ButtonGroup
122
+
123
+ | Propriedade | Tipo | Padrão | Descrição |
124
+ |---|---|---|---|
125
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção do bloco e do colapso das bordas. |
126
+ | `shape` | `'default' \| 'pill'` | `'default'` | Geometria das extremidades externas do grupo. |
127
+
128
+ ### Propriedades de ButtonGroupSeparator
129
+
130
+ | Propriedade | Tipo | Padrão | Descrição |
131
+ |---|---|---|---|
132
+ | `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Direção do traço divisor; use vertical em grupos horizontais. |
133
+
134
+ ### Propriedades de ButtonGroupText
135
+
136
+ | Propriedade | Tipo | Padrão | Descrição |
137
+ |---|---|---|---|
138
+ | `asChild` | `boolean` | `false` | Renderiza como o filho para assumir outra semântica sem perder o estilo. |
@@ -17,7 +17,7 @@ render(
17
17
 
18
18
  ## Intervalo
19
19
 
20
- mode=range guarda { from, to } — o padrão pra filtrar sessões por janela de datas. O primeiro clique fixa o início; o segundo, o fim.
20
+ mode=range guarda { from, to } — o padrão para filtrar sessões por janela de datas. O primeiro clique fixa o início; o segundo, o fim.
21
21
 
22
22
  ```tsx preview
23
23
  const [week, setWeek] = useState<DateRange | undefined>({
@@ -37,7 +37,7 @@ render(
37
37
 
38
38
  ## Navegação por dropdown
39
39
 
40
- captionLayout=dropdown troca o título do mês por seletores de mês e ano — bom pra pular pra um período distante (ex.: histórico de um repositório) sem clicar mês a mês.
40
+ captionLayout=dropdown troca o título do mês por seletores de mês e ano — bom para pular para um período distante (ex.: histórico de um repositório) sem clicar mês a mês.
41
41
 
42
42
  ```tsx preview
43
43
  <Calendar
@@ -47,16 +47,16 @@ captionLayout=dropdown troca o título do mês por seletores de mês e ano — b
47
47
  />
48
48
  ```
49
49
 
50
- ## Props
50
+ ## Propriedades de Calendar
51
51
 
52
- | Prop | Tipo | Default | Descrição |
52
+ | Propriedade | Tipo | Padrão | Descrição |
53
53
  |---|---|---|---|
54
54
  | `mode` | `'single' \| 'multiple' \| 'range'` | | O tipo de seleção — define o formato de selected/onSelect (Date, Date[] ou { from, to }). |
55
55
  | `selected` | `Date \| Date[] \| DateRange` | | A seleção atual no modo controlado — o formato segue o mode. Pareie com onSelect. |
56
56
  | `onSelect` | `(selected) => void` | | Chamado quando o usuário escolhe uma data. O argumento segue o mode. |
57
57
  | `defaultMonth` | `Date` | | O mês exibido ao montar, sem afetar a seleção. |
58
58
  | `captionLayout` | `'label' \| 'dropdown' \| 'dropdown-months' \| 'dropdown-years'` | `'label'` | Como o título do mês aparece — label é texto fixo; dropdown vira seletores de mês e ano. |
59
- | `numberOfMonths` | `number` | `1` | Quantos meses mostrar lado a lado — útil pra escolher um intervalo longo. |
59
+ | `numberOfMonths` | `number` | `1` | Quantos meses mostrar lado a lado — útil para escolher um intervalo longo. |
60
60
  | `disabled` | `Matcher` | | Datas não selecionáveis — uma Date, um array, um { from, to } ou um predicado (date) => boolean. |
61
61
  | `buttonVariant` | `Button['variant']` | `'ghost'` | A variante dos botões de navegação (anterior/próximo). |
62
62
  | `showOutsideDays` | `boolean` | `true` | Mostra os dias do mês vizinho que completam a primeira e a última semana. |
@@ -10,7 +10,7 @@ O uso mais comum: a superfície de conteúdo em repouso (`rounded-xl` + `border`
10
10
 
11
11
  ## Estruturado (header / conteúdo / rodapé)
12
12
 
13
- Pra painel com estrutura: cada slot é dono do próprio padding (como o Dialog). CardTitle/CardDescription no header; CardFooter alinha as ações.
13
+ Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog). CardTitle/CardDescription no header; CardFooter alinha as ações.
14
14
 
15
15
  ```tsx preview col
16
16
  <Card>
@@ -18,9 +18,9 @@ Pra painel com estrutura: cada slot é dono do próprio padding (como o Dialog).
18
18
  <CardTitle>Empresa X</CardTitle>
19
19
  <CardDescription>2 repositórios · 3 agentes vinculados.</CardDescription>
20
20
  </CardHeader>
21
- <CardContent>
21
+ <CardBody>
22
22
  <p className="text-sm text-muted-foreground">Última sessão concluída há 2 horas.</p>
23
- </CardContent>
23
+ </CardBody>
24
24
  <CardFooter className="gap-2">
25
25
  <Button size="sm">Abrir sessão</Button>
26
26
  <Button size="sm" variant="outline">Ver repositórios</Button>
@@ -38,11 +38,11 @@ Pra painel com estrutura: cada slot é dono do próprio padding (como o Dialog).
38
38
  <CardTitle>Skill code-style</CardTitle>
39
39
  <CardDescription>Padrão softize de código e microcopy.</CardDescription>
40
40
  </CardHeader>
41
- <CardContent>
41
+ <CardBody>
42
42
  <p className="text-sm text-muted-foreground">Vinculada a 4 agentes neste workspace.</p>
43
- </CardContent>
43
+ </CardBody>
44
44
  <CardFooter className="justify-between border-t">
45
- <Badge variant="success">Publicada</Badge>
45
+ <Badge context="success">Publicada</Badge>
46
46
  <Button size="sm" variant="outline">Editar skill</Button>
47
47
  </CardFooter>
48
48
  </Card>
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Um slide por vez
2
2
 
3
- Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext pra navegar. As setas ficam fora do trilho (-left-12/-right-12), então reserve a margem lateral no entorno.
3
+ Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext para navegar. As setas ficam fora do trilho (-left-12/-right-12), então reserve a margem lateral no entorno.
4
4
 
5
5
  ```tsx preview
6
6
  <Carousel className="mx-12 w-full max-w-xs">
@@ -28,7 +28,7 @@ Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext
28
28
 
29
29
  ## Vários por vista
30
30
 
31
- O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três slides por vez. Bom pra galeria de workspaces ou repositórios.
31
+ O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três slides por vez. Bom para galeria de workspaces ou repositórios.
32
32
 
33
33
  ```tsx preview
34
34
  <Carousel className="mx-12 w-full max-w-sm" opts={{ align: 'start' }}>
@@ -48,7 +48,7 @@ O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três
48
48
 
49
49
  ## Vertical
50
50
 
51
- orientation=vertical empilha os slides; as setas migram pra cima e pra baixo (-top-12/-bottom-12). Dê uma altura ao CarouselContent pra delimitar a vista.
51
+ orientation=vertical empilha os slides; as setas migram para cima e para baixo (-top-12/-bottom-12). Dê uma altura ao CarouselContent para delimitar a vista.
52
52
 
53
53
  ```tsx preview
54
54
  <Carousel className="w-full max-w-xs" orientation="vertical">
@@ -74,12 +74,17 @@ orientation=vertical empilha os slides; as setas migram pra cima e pra baixo (-t
74
74
  </Carousel>
75
75
  ```
76
76
 
77
- ## Props
77
+ ## Propriedades de Carousel
78
78
 
79
- | Prop | Tipo | Default | Descrição |
79
+ | Propriedade | Tipo | Padrão | Descrição |
80
80
  |---|---|---|---|
81
- | `orientation (Carousel)` | `'horizontal' \| 'vertical'` | `'horizontal'` | Eixo do deslize vertical empilha os slides e gira as setas pro topo/base. |
82
- | `opts (Carousel)` | `CarouselOptions` | | Opções do embla (ex.: { loop: true }, { align: "start" }). Repassadas direto pro motor. |
83
- | `setApi (Carousel)` | `(api: CarouselApi) => void` | | Recebe a instância do embla pra controlar de fora (scrollTo, ler o slide ativo). |
84
- | `plugins (Carousel)` | `CarouselPlugin` | | Plugins do embla (ex.: autoplay) anexados ao carousel. |
85
- | `className (CarouselItem)` | `string` | | O basis decide quantos slides cabem na vista (basis-full, basis-1/2, basis-1/3). |
81
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Eixo do deslocamento. No modo vertical, os slides são empilhados e as setas apontam para cima e para baixo. |
82
+ | `opts` | `CarouselOptions` | | Opções repassadas ao Embla, como `{ loop: true }` ou `{ align: 'start' }`. |
83
+ | `setApi` | `(api: CarouselApi) => void` | | Recebe a instância para controle externo, como navegar com `scrollTo` ou ler o slide ativo. |
84
+ | `plugins` | `CarouselPlugin[]` | | Plugins do Embla associados ao carrossel, como autoplay. |
85
+
86
+ ## Propriedades de CarouselItem
87
+
88
+ | Propriedade | Tipo | Padrão | Descrição |
89
+ |---|---|---|---|
90
+ | `className` | `string` | | Classes de dimensão; a base define quantos slides cabem na área visível. |
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Conversa com resposta integral
2
2
 
3
- Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por dentro (estado, loading, auto-scroll; **Enter** envia, **Shift+Enter** quebra linha) — a inteligência vem da prop `send`. Com o composer vazio, **↑** recupera as mensagens anteriores do usuário e **↓** volta em direção ao rascunho; durante a edição, as setas continuam movendo o cursor normalmente. O `greeting` é o estado vazio (centrado; some quando a conversa começa e NÃO entra no transcript). Dê altura ao container.
3
+ Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por dentro (estado, loading, auto-scroll; **Enter** envia, **Shift+Enter** quebra linha) — a inteligência vem da prop `send`. Com o composer vazio, **↑** recupera as mensagens anteriores do usuário e **↓** volta em direção ao rascunho; durante a edição, as setas continuam movendo o cursor normalmente. O `greeting` é o estado vazio (centrado; some quando a conversa começa e não entra no transcript). Dê altura ao container.
4
4
 
5
5
  ```tsx preview
6
6
  <div className="h-96 rounded-lg border">
@@ -9,7 +9,7 @@ Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por den
9
9
  send={async (messages) => {
10
10
  await new Promise((r) => setTimeout(r, 500))
11
11
  const last = messages[messages.length - 1]
12
- return `Você disse: "${last.content}". (Num app real, aqui rodaria o agente.)`
12
+ return `Você disse: "${last.content}". (Em um app real, aqui rodaria o agente.)`
13
13
  }}
14
14
  />
15
15
  </div>
@@ -1,6 +1,6 @@
1
- ## Básico
1
+ ## Escolha booleana
2
2
 
3
- Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defaultChecked pro modo não controlado.
3
+ Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defaultChecked para o modo não controlado.
4
4
 
5
5
  ```tsx preview
6
6
  <div className="flex items-center gap-2">
@@ -11,7 +11,7 @@ Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a caixa. defa
11
11
 
12
12
  ## Controlado
13
13
 
14
- onCheckedChange recebe boolean | 'indeterminate' — compare com true pra guardar um boolean.
14
+ onCheckedChange recebe boolean | 'indeterminate' — compare com true para guardar um boolean.
15
15
 
16
16
  ```tsx preview
17
17
  const [autoReview, setAutoReview] = useState(true)
@@ -30,7 +30,7 @@ render(
30
30
 
31
31
  ## Lista de opções
32
32
 
33
- Várias caixas, um estado: o conjunto marcado é a lista de valores — o padrão pra anexar skills a um agente.
33
+ Várias caixas, um estado: o conjunto marcado é a lista de valores — o padrão para anexar skills a um agente.
34
34
 
35
35
  ```tsx preview col-start
36
36
  const [skills, setSkills] = useState(['clean-code', 'test'])
@@ -65,11 +65,11 @@ disabled esmaece a caixa e o rótulo em par (peer-disabled no Label) — marcado
65
65
  </div>
66
66
  ```
67
67
 
68
- ## Props
68
+ ## Propriedades de Checkbox
69
69
 
70
- | Prop | Tipo | Default | Descrição |
70
+ | Propriedade | Tipo | Padrão | Descrição |
71
71
  |---|---|---|---|
72
72
  | `checked` | `boolean \| 'indeterminate'` | | O estado, no modo controlado — parear com onCheckedChange. |
73
- | `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | | Chamado a cada alternância. Pra guardar um boolean, compare com true. |
73
+ | `onCheckedChange` | `(checked: boolean \| 'indeterminate') => void` | | Chamado a cada alternância. Para guardar um boolean, compare com true. |
74
74
  | `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
75
75
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
@@ -5,7 +5,7 @@ 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 pros agentes via MCP.
8
+ valida as convenções e expõe o estado vivo para os agentes via MCP.
9
9
 
10
10
  ## Gates
11
11
 
@@ -38,7 +38,7 @@ mesma CLI.
38
38
  ## Geração e introspecção
39
39
 
40
40
  > As declarações (`description` de entidades/actions) são a fonte; o `gen` as projeta. O manifest
41
- > é um lockfile commitado diff de manifest é ouro pra review.
41
+ > é um lockfile versionado. A diferença do manifest torna a revisão objetiva.
42
42
 
43
43
  ```bash
44
44
  opus gen # manifest / openapi / docs / stubs a partir do opus.config.ts
@@ -57,17 +57,17 @@ opus create meu-cliente --monorepo # a RAIZ de um workspace (apps/* + packages/
57
57
  opus create apps/portal # dentro de um workspace: só o app (modo detectado)
58
58
  opus setup # grava opus.json e materializa a camada específica do SDK
59
59
  opus list # lista os templates disponíveis
60
- opus add action-form # copia um template do catálogo pro projeto
60
+ opus add action-form # copia um template do catálogo para o projeto
61
61
  ```
62
62
 
63
63
  O esqueleto do `create` versiona com o Opus (sai do mesmo pacote que o SDK que ele
64
64
  configura) e nasce com os gates verdes: domínio-exemplo canônico, teste, manifest e o dev
65
- server pronto pro preview do Maestro. O método geral, a memória e a revisão vêm da Base
65
+ server pronto para o preview do Maestro. O método geral, a memória e a revisão vêm da Base
66
66
  depois de `pnpm run setup`. Dois modos, por detecção:
67
67
  repo standalone (template inteiro) ou **app em monorepo** (dentro de um workspace pnpm:
68
68
  só os arquivos do app; o que a raiz precisa ter vira aviso, sem clobber).
69
69
 
70
- ## MCP — estado vivo pros agentes
70
+ ## MCP — estado vivo para os agentes
71
71
 
72
72
  > O server MCP expõe introspecção, check e scaffold de action. É como um agente lê a estrutura e cria
73
73
  > action no formato canônico sem decorar convenção.
@@ -1,4 +1,4 @@
1
- ## Básico
1
+ ## Seção recolhível
2
2
 
3
3
  CollapsibleTrigger alterna o CollapsibleContent — o Trigger já é o <button>. defaultOpen deixa o estado com o componente.
4
4
 
@@ -18,7 +18,7 @@ CollapsibleTrigger alterna o CollapsibleContent — o Trigger já é o <button>.
18
18
 
19
19
  ## Controlado
20
20
 
21
- open + onOpenChange põem o estado nas suas mãos — dá pra refletir no gatilho (aqui o chevron gira) ou guardar a preferência.
21
+ open + onOpenChange põem o estado nas suas mãos — dá para refletir no gatilho (aqui o chevron gira) ou guardar a preferência.
22
22
 
23
23
  ```tsx preview col
24
24
  const [open, setOpen] = useState(false)
@@ -54,11 +54,11 @@ disabled no Collapsible trava o gatilho — a seção fica fixa no estado atual
54
54
  </Collapsible>
55
55
  ```
56
56
 
57
- ## Props
57
+ ## Propriedades de Collapsible
58
58
 
59
- | Prop | Tipo | Default | Descrição |
59
+ | Propriedade | Tipo | Padrão | Descrição |
60
60
  |---|---|---|---|
61
- | `defaultOpen (Collapsible)` | `boolean` | `false` | Estado inicial no modo não controlado. |
62
- | `open (Collapsible)` | `boolean` | | Estado no modo controlado pareie com onOpenChange. |
63
- | `onOpenChange (Collapsible)` | `(open: boolean) => void` | | Chamado a cada abertura ou fechamento. |
64
- | `disabled (Collapsible)` | `boolean` | `false` | Trava o gatilho a seção fica presa no estado atual. |
61
+ | `defaultOpen` | `boolean` | `false` | Estado inicial no modo não controlado. |
62
+ | `open` | `boolean` | | Estado no modo controlado. Use com `onOpenChange`. |
63
+ | `onOpenChange` | `(open: boolean) => void` | | Chamado a cada abertura ou fechamento. |
64
+ | `disabled` | `boolean` | `false` | Bloqueia o gatilho e mantém a seção no estado atual. |