@softize/opus 18.1.0 → 18.2.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.
- package/CHANGELOG.md +75 -0
- package/PROMOTED.md +4 -5
- package/README.md +5 -4
- package/bin/cli.mjs +4 -0
- package/docs/adr/0004-page-content-state-is-composed.md +3 -0
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +6 -2
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +6 -1
- package/docs/adr/0014-structural-headers-do-not-carry-description.md +2 -2
- package/docs/adr/0015-action-size-follows-interaction-density.md +4 -3
- package/docs/adr/{0012-modal-header-only-names-the-surface.md → 0018-modal-header-only-names-the-surface.md} +4 -1
- package/docs/adr/{0016-productive-surfaces-use-compact-density.md → 0019-productive-surfaces-use-compact-density.md} +4 -1
- package/docs/code-style.md +2 -2
- package/docs/consumer-upgrade-propagation.md +1 -1
- package/docs/data-products.md +5 -3
- package/docs/protocol.md +6 -6
- package/docs/releasing.md +28 -4
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +11 -1
- package/src/auth/drivers/jwt.ts +2 -1
- package/src/core/presentation.ts +143 -58
- package/src/core/runtime.ts +25 -4
- package/src/core/types.ts +4 -4
- package/src/mcp/index.ts +9 -0
- package/src/ui/components/patterns/content-header.tsx +1 -1
- package/src/ui/components/patterns/form.tsx +1 -1
- package/src/ui/components/patterns/presentation.tsx +199 -60
- package/src/ui/components/patterns/sidebar.tsx +1 -1
- package/src/ui/components/patterns/split.tsx +5 -2
- package/src/ui/components/patterns/surface-assistant.tsx +74 -0
- package/src/ui/components/primitives/card.tsx +1 -1
- package/src/ui/components/primitives/detail.tsx +7 -7
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/select.tsx +1 -1
- package/src/ui/docs/content/action-form-dialog.md +11 -4
- package/src/ui/docs/content/action-form.md +7 -16
- package/src/ui/docs/content/action-list-dialog.md +4 -6
- package/src/ui/docs/content/action-list.md +46 -4
- package/src/ui/docs/content/action-trigger.md +9 -5
- package/src/ui/docs/content/action-view.md +12 -8
- package/src/ui/docs/content/actions.md +36 -13
- package/src/ui/docs/content/ai.md +26 -7
- package/src/ui/docs/content/alert.md +4 -3
- package/src/ui/docs/content/aspect-ratio.md +2 -2
- package/src/ui/docs/content/auth.md +25 -10
- package/src/ui/docs/content/avatar.md +1 -1
- package/src/ui/docs/content/badge.md +2 -2
- package/src/ui/docs/content/breadcrumb.md +3 -2
- package/src/ui/docs/content/button.md +31 -7
- package/src/ui/docs/content/calendar.md +1 -1
- package/src/ui/docs/content/card.md +1 -1
- package/src/ui/docs/content/carousel.md +14 -3
- package/src/ui/docs/content/chat.md +1 -1
- package/src/ui/docs/content/cli.md +13 -7
- package/src/ui/docs/content/command.md +34 -2
- package/src/ui/docs/content/composer.md +1 -1
- package/src/ui/docs/content/content.md +5 -4
- package/src/ui/docs/content/customization.md +1 -1
- package/src/ui/docs/content/cycle.md +7 -5
- package/src/ui/docs/content/data-state.md +6 -5
- package/src/ui/docs/content/data.md +3 -3
- package/src/ui/docs/content/detail.md +3 -2
- package/src/ui/docs/content/dialog.md +2 -2
- package/src/ui/docs/content/dictionary-value.md +1 -1
- package/src/ui/docs/content/dock.md +23 -2
- package/src/ui/docs/content/dot.md +0 -2
- package/src/ui/docs/content/drawer.md +1 -1
- package/src/ui/docs/content/empty.md +1 -4
- package/src/ui/docs/content/events.md +1 -1
- package/src/ui/docs/content/field.md +20 -11
- package/src/ui/docs/content/getting-started.md +4 -2
- package/src/ui/docs/content/icon-picker.md +2 -2
- package/src/ui/docs/content/input-otp.md +2 -0
- package/src/ui/docs/content/input.md +2 -3
- package/src/ui/docs/content/item.md +5 -4
- package/src/ui/docs/content/kbd.md +2 -1
- package/src/ui/docs/content/mcp.md +10 -4
- package/src/ui/docs/content/menu.md +27 -0
- package/src/ui/docs/content/page.md +19 -5
- package/src/ui/docs/content/pagination.md +9 -2
- package/src/ui/docs/content/popover.md +2 -2
- package/src/ui/docs/content/presentation.md +85 -58
- package/src/ui/docs/content/progress.md +2 -6
- package/src/ui/docs/content/runtime.md +8 -5
- package/src/ui/docs/content/scheduler.md +1 -1
- package/src/ui/docs/content/select.md +13 -8
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +1 -1
- package/src/ui/docs/content/slider.md +4 -4
- package/src/ui/docs/content/spinner.md +3 -3
- package/src/ui/docs/content/split.md +80 -19
- package/src/ui/docs/content/tabs.md +6 -6
- package/src/ui/docs/content/testing.md +4 -2
- package/src/ui/docs/content/toast.md +3 -5
- package/src/ui/docs/content/toggle.md +37 -0
- package/src/ui/docs/content/tooltip.md +4 -3
- package/src/ui/docs/content/truncate.md +3 -2
- package/src/ui/docs/content/ui.md +3 -1
- package/src/ui/docs/content/upgrading.md +43 -13
- package/src/ui/docs/doc-client.tsx +1 -1
- package/src/ui/docs/registry.tsx +30 -5
- package/src/ui/meta.ts +5 -5
- package/src/ui/react.tsx +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,79 @@ Depois de qualquer bump, rode os gates (`typecheck` · `test` · `opus check` ·
|
|
|
7
7
|
`opus copy --check` · `base copy check` · `manifest:check`) — eles apontam o que a
|
|
8
8
|
mudança cobra do seu código.
|
|
9
9
|
|
|
10
|
+
## 18.2.0 — 2026-09-16
|
|
11
|
+
|
|
12
|
+
`Presentation` passa a aceitar um body serializável baseado em componente. O contrato continua
|
|
13
|
+
definindo rota, superfície, navegação e ações, enquanto a aplicação fornece o conteúdo React em
|
|
14
|
+
tempo de execução. Assim, uma página pode adotar a casca dirigida por spec sem precisar migrar de
|
|
15
|
+
uma vez toda a implementação interna para actions declarativas.
|
|
16
|
+
|
|
17
|
+
Recursos podem declarar um gatilho de assistência contextual em `assistant`. A aplicação fornece o
|
|
18
|
+
painel e os dados vivos do recurso por `assistant.render`; identidade, autorização e demais dados
|
|
19
|
+
não entram no manifest. O novo `SurfaceAssistant`, também disponível pela API pública, divide
|
|
20
|
+
somente o body de Page, Dialog ou Drawer. Cabeçalho e rodapé permanecem em toda a largura, e o
|
|
21
|
+
gatilho sai do cabeçalho enquanto o painel aberto assume a identidade visual da assistência.
|
|
22
|
+
|
|
23
|
+
O split contextual usa um único separador redimensionável, sem sobrepor uma segunda borda entre o
|
|
24
|
+
conteúdo e o painel. O conteúdo principal permanece montado durante a conversa e volta a ocupar
|
|
25
|
+
toda a largura quando ela é fechada.
|
|
26
|
+
|
|
27
|
+
## 18.1.1 — 2026-09-16
|
|
28
|
+
|
|
29
|
+
**Correção de segurança.** Quem executa tools de IA só roda o que `aiTools()` anunciou. Até aqui, o
|
|
30
|
+
servidor MCP executava em `CallTool` qualquer action registrada, e o agente co-locado executava
|
|
31
|
+
qualquer nome de tool que o modelo emitisse. Um cliente MCP, um modelo ou um prompt injetado podia
|
|
32
|
+
rodar uma action sem `ai.enabled` — inclusive destrutiva — dentro da autorização do contexto
|
|
33
|
+
resolvido. Os dois caminhos agora recusam o nome fora do conjunto exposto, com a mesma resposta
|
|
34
|
+
para action inexistente e para action registrada mas não exposta, sem revelar quais existem.
|
|
35
|
+
Nenhuma mudança é necessária em quem já marcava com `ai.enabled` as actions que expõe; quem
|
|
36
|
+
dependia de chamar pelo MCP uma action não marcada precisa marcá-la.
|
|
37
|
+
|
|
38
|
+
Uma action que não é `public` passa a exigir usuário ANTES de rodar os loaders. Antes, os
|
|
39
|
+
`loads` consultavam dados para um chamador anônimo, que recebia o erro do loader — um
|
|
40
|
+
`not_found`, por exemplo — e podia usar essa diferença para descobrir se um registro existe. O
|
|
41
|
+
`authorize` continua depois dos loaders, porque depende do que eles carregam.
|
|
42
|
+
|
|
43
|
+
`RadioGroupItem` passa a ter a classe `peer`, como `Checkbox` e `Switch`: o `Label` associado
|
|
44
|
+
esmaece quando o item está desabilitado, como a documentação já descrevia. Em `DetailGroup` com
|
|
45
|
+
moldura e orientação horizontal, a largura padrão da coluna de rótulos passa a ser uma classe, e
|
|
46
|
+
uma classe do consumidor (`[--detail-label-width:9rem]`) volta a substituí-la; antes, só `style`
|
|
47
|
+
conseguia.
|
|
48
|
+
|
|
49
|
+
A documentação publicada foi revisada por inteiro, e as 92 páginas foram abertas num navegador
|
|
50
|
+
headless sem erro de console nem de preview. O exemplo principal de Presentation voltou a
|
|
51
|
+
renderizar: ele usava funções que não estavam no escopo dos previews e lançava `ReferenceError`.
|
|
52
|
+
Um exemplo do `IconPicker` declarava `Icon`, nome que o escopo já fornece, e mostrava um erro de
|
|
53
|
+
sintaxe no lugar do preview. Um gate novo compila cada preview com o escopo da sua página, do jeito
|
|
54
|
+
que o site o executa, e reprova nome ausente ou redeclarado; o anterior só conferia tags JSX. Sessenta e quatro páginas foram
|
|
55
|
+
corrigidas contra o código: props, defaults e tipos que não batiam, exemplos que não compilavam ou ensinavam padrões
|
|
56
|
+
substituídos pelas versões 16 a 18, e afirmações que o código não sustenta. Entre elas, `auth.md`
|
|
57
|
+
deixa de sugerir que o runtime aplica um campo `auth` inexistente, e `upgrading.md` passa a incluir
|
|
58
|
+
`pnpm run setup` e os gates de copy, sem os quais o fluxo de upgrade falhava no primeiro gate.
|
|
59
|
+
|
|
60
|
+
`opus check --help` lista as regras de Produto de Dados. As ADRs que dividiam número foram
|
|
61
|
+
renumeradas: a do cabeçalho modal passa a 0018 e a da densidade compacta, a 0019; um gate impede
|
|
62
|
+
nova colisão. O guia de release passa a dizer que a documentação é publicada à parte, com
|
|
63
|
+
`pnpm deploy:docs`. A skill `build-opus-ui` passa a ensinar `placement` nos filtros e o
|
|
64
|
+
`ButtonGroup` nos footers modais.
|
|
65
|
+
|
|
66
|
+
### Correções do histórico
|
|
67
|
+
|
|
68
|
+
Estas entradas publicadas descrevem algo diferente do que o código daquela versão fez. Elas não
|
|
69
|
+
foram reescritas; a correção fica registrada aqui.
|
|
70
|
+
|
|
71
|
+
- **17.2.1 nunca foi publicada.** O conteúdo daquela entrada — `renderMessageActions` nas mensagens
|
|
72
|
+
enviadas, `activity=""` e o `title` das tools MCP — saiu na 18.0.0.
|
|
73
|
+
- **17.0.0 e 17.2.0 mudaram a composição explícita dentro de `PageShell` sem aviso de quebra.** A
|
|
74
|
+
17.0.0 passou a exigir `PageHeader` onde a 16.x exigia `PageIntro`, e a 17.2.0 voltou a exigir
|
|
75
|
+
`PageIntro`. Desde a 18.0.0, ambos são opcionais e a página exige um único heading principal.
|
|
76
|
+
- **18.1.0:** `Item size="sm"` reduz também o espaço entre regiões, para `0.625rem`, e não somente o
|
|
77
|
+
padding vertical. A mesma versão trocou o fechamento de Dialog e Drawer, que na 18.0.1 era um
|
|
78
|
+
`Button` `icon`, pelo `CloseButton` (`neutral`, `subtle`, forma de pílula e `icon-sm`), com
|
|
79
|
+
a nova prop `closeSize`; nenhum dos dois foi anunciado. Ela também removeu breakpoints responsivos
|
|
80
|
+
e mudou o footer padrão do `ActionFormDialog`; quem tinha testes visuais ou telas abaixo de
|
|
81
|
+
`64rem` precisa revisá-los.
|
|
82
|
+
|
|
10
83
|
## 18.1.0 — 2026-09-15
|
|
11
84
|
|
|
12
85
|
A UI passa a assumir layout desktop fixo com largura mínima suportada de `64rem`. Breakpoints de
|
|
@@ -107,6 +180,8 @@ a API imperativa, usam `outline`; a decisão principal continua `solid`.
|
|
|
107
180
|
|
|
108
181
|
## 17.2.1 — 2026-09-12
|
|
109
182
|
|
|
183
|
+
> Esta versão nunca foi publicada no npm; o conteúdo abaixo saiu na 18.0.0.
|
|
184
|
+
|
|
110
185
|
O `Chat` passa a renderizar `renderMessageActions` também nas mensagens enviadas. Data, cópia e
|
|
111
186
|
outras ações contextuais podem usar a mesma extensão discreta nos dois lados da conversa.
|
|
112
187
|
`activity=""` oferece o indicador compacto, com somente os pontos centralizados e “Pensando…”
|
package/PROMOTED.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# Enhancements promovidas ao Opus
|
|
2
2
|
|
|
3
3
|
O registro CURADO da régua "o Opus cresce por reincidência". O fluxo vivo NÃO passa por
|
|
4
|
-
edição manual deste arquivo:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
acontecem (aberta = pendente, fechada = decidida). Enhancement aceita com **n ≥ 2**
|
|
4
|
+
edição manual deste arquivo: cada apontamento vira uma **Issue no repo do Opus**
|
|
5
|
+
(`github.com/softize-dev/opus`), `type` **enhancement** ou **bug**, onde a triagem e a
|
|
6
|
+
decisão acontecem (aberta = pendente, fechada = decidida). O pacote não coleta nada do
|
|
7
|
+
projeto consumidor por conta própria. Enhancement aceita com **n ≥ 2**
|
|
9
8
|
ocorrências reais — comportamento se paga na reincidência; estilo e conveniência não.
|
|
10
9
|
Bug (defeito NO Opus) aciona com n=1: vira fix + CHANGELOG, **não** entra neste ledger.
|
|
11
10
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Opus
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Pacote único `@softize/opus` com subpath exports (core + adapters). Uma versão, sem semver por módulo.
|
|
4
4
|
|
|
5
5
|
Protocolo de actions de ponta a ponta para TypeScript. Declare uma vez — input, autorização, execução, auditoria, feedback — e deixe os adapters materializarem a action na interface, no cliente, no servidor e no log.
|
|
6
6
|
|
|
@@ -43,6 +43,7 @@ Um pacote (`@softize/opus`), uma versão. Cada categoria abaixo é um **subpath
|
|
|
43
43
|
| `@softize/opus/testing` | — | Harness de teste de actions pela fronteira do contrato (experimental) |
|
|
44
44
|
| `@softize/opus/dsl` | — | Expressões declarativas avaliadas em `load` e em consultas |
|
|
45
45
|
| `@softize/opus/seed` | — | Declaração e binding de datasets verificáveis operados pela CLI |
|
|
46
|
+
| `@softize/opus/presentation` | — | Presentations portáteis: `definePresentation`, invocação e rotas |
|
|
46
47
|
| `@softize/opus/vite` | — | Plugins Vite: runtime em modo design e auth de sessão fixa |
|
|
47
48
|
|
|
48
49
|
Os drivers são resolvidos por subpath ESM (no estilo do Drizzle): `@softize/opus/server/fastify`, `@softize/opus/data/kysely`.
|
|
@@ -90,7 +91,7 @@ await app.listen({ port: 3000 })
|
|
|
90
91
|
src/
|
|
91
92
|
core/ schema/ server/ client/ ui/ data/ auth/ audit/
|
|
92
93
|
log/ queue/ events/ scheduler/ storage/ cache/ ai/ mcp/
|
|
93
|
-
observability/ testing/ dsl/ seed/ vite/
|
|
94
|
+
observability/ testing/ dsl/ seed/ vite/ presentation/
|
|
94
95
|
registry/ # scaffolds + skills Opus — geração e conhecimento do SDK, não runtime
|
|
95
96
|
bin/ # CLI (opus create/setup/gen/copy/check/db/seed/pre-push/introspect/mcp) + libs
|
|
96
97
|
docs/
|
|
@@ -117,8 +118,8 @@ O contrato não oferece reset/truncate, e `apply` precisa convergir quando repet
|
|
|
117
118
|
|
|
118
119
|
## Status
|
|
119
120
|
|
|
120
|
-
- **
|
|
121
|
-
- **
|
|
121
|
+
- **Hoje**: 22 superfícies, suíte vitest com cobertura medida por `pnpm test:cov`. O threshold de 100% em `vitest.config.ts` é aspiracional e não faz parte do gate de release (ver [docs/releasing.md](docs/releasing.md)).
|
|
122
|
+
- **Próximos**: drivers adicionais (Hono, Drizzle, ArkType, Vue, Inngest, Redis events) e o plano de migração da Conversya.
|
|
122
123
|
|
|
123
124
|
## Desenvolvimento
|
|
124
125
|
|
package/bin/cli.mjs
CHANGED
|
@@ -426,6 +426,10 @@ Regras da UI (@softize/opus/ui):
|
|
|
426
426
|
unpaired-ui-surface — superfície sem o foreground do par (bg-card sem
|
|
427
427
|
text-card-foreground, bg-popover sem text-popover-foreground)
|
|
428
428
|
|
|
429
|
+
Regras dos Produtos de Dados (defineDataProduct):
|
|
430
|
+
data-product-* — declaração exportada, id e versão válidos, sem duplicata,
|
|
431
|
+
interfaces e entidades que existem no domínio
|
|
432
|
+
|
|
429
433
|
Exit ≠ 0 se houver violação. Sem nenhuma action: projeto marcado (opus.json) passa
|
|
430
434
|
vacuamente; sem marcador, falha — gate vazio não é aprovação. Default dir: cwd.
|
|
431
435
|
`)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# ADR 0004 — O estado integral do conteúdo é composto dentro de Page
|
|
2
2
|
|
|
3
|
+
- **Status:** aceita, com adendo.
|
|
4
|
+
- **Data:** 2026-09-04.
|
|
5
|
+
|
|
3
6
|
> **Atualização (2026-09-09).** A decisão original preservava o cabeçalho da página em todos os
|
|
4
7
|
> estados. Ela foi invertida: `PageState` passa a ocultá-lo em `loading`, `error` e `empty`, e a
|
|
5
8
|
> restaurá-lo em `ready`. A lista de responsabilidades abaixo já descreve o comportamento novo; o
|
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
> **Atualização (2026-09-09).** Parcialmente substituída pela ADR 0009 quanto a `PageMeta` e ao
|
|
7
7
|
> `count` de `Page`, e complementada pela ADR 0010, que acrescenta as apresentações `default` e
|
|
8
|
-
> `bar` ao mesmo header.
|
|
8
|
+
> `bar` ao mesmo header.
|
|
9
9
|
>
|
|
10
|
-
> **Atualização (2026-09-11).** As ADRs
|
|
10
|
+
> **Atualização (2026-09-11).** As ADRs 0018 e 0014 removem Description dos headers de Page,
|
|
11
11
|
> Dialog e Drawer. Contexto relevante começa no body.
|
|
12
|
+
>
|
|
13
|
+
> **Atualização (2026-09-16).** O corpo abaixo descreve a anatomia da época em que foi escrito, não a
|
|
14
|
+
> vigente: a apresentação `bar` da ADR 0010 saiu com a ADR 0011, e nenhum header estrutural carrega
|
|
15
|
+
> mais descrição (ADRs 0018 e 0014). A anatomia atual está na documentação de cada família.
|
|
12
16
|
|
|
13
17
|
## Contexto
|
|
14
18
|
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
- **Status:** aceita.
|
|
4
4
|
- **Data:** 2026-09-10.
|
|
5
|
-
- **
|
|
5
|
+
- **Substitui:** ADR 0010.
|
|
6
6
|
|
|
7
7
|
> **Atualização (2026-09-13).** A ADR 0016 separa o chrome persistente da introdução e do
|
|
8
8
|
> cabeçalho de uma coleção. `PageHeader` passa a declarar navegação e ações globais para a barra;
|
|
9
9
|
> `PageIntro` permanece opcional no conteúdo e `Content` nomeia coleções.
|
|
10
|
+
>
|
|
11
|
+
> **Atualização (2026-09-16).** Desde a 18.0.0, a composição explícita dentro do shell aceita
|
|
12
|
+
> `PageHeader`, `PageIntro` e `PageFooter` como opcionais e exige exatamente um heading principal —
|
|
13
|
+
> `PageTitle`, `Content level={1}` ou um `PageState` ativo. As frases abaixo que pedem `PageIntro`
|
|
14
|
+
> "sem `PageHeader`" descrevem a regra da 17.2 e não valem mais.
|
|
10
15
|
|
|
11
16
|
## Contexto
|
|
12
17
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
- **Status:** aceita.
|
|
4
4
|
- **Data:** 2026-09-11.
|
|
5
|
-
- **Complementa:** ADRs 0005, 0011 e
|
|
5
|
+
- **Complementa:** ADRs 0005, 0011 e 0018.
|
|
6
6
|
|
|
7
7
|
## Contexto
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ superfície e misturava o nome do recurso com instruções e consequências da t
|
|
|
13
13
|
## Decisão
|
|
14
14
|
|
|
15
15
|
Headers estruturais contêm navegação opcional, título e actions. Page não oferece a propriedade
|
|
16
|
-
`description` nem `PageDescription`; Dialog e Drawer seguem a mesma regra conforme a ADR
|
|
16
|
+
`description` nem `PageDescription`; Dialog e Drawer seguem a mesma regra conforme a ADR 0018.
|
|
17
17
|
|
|
18
18
|
Contexto que altera compreensão ou decisão aparece no início do body. Ele pode ser texto, `Alert`,
|
|
19
19
|
`Content` ou outra composição adequada. `PageState`, `Alert`, `Empty`, campos, métricas e seções
|
|
@@ -21,10 +21,11 @@ risco.
|
|
|
21
21
|
|
|
22
22
|
- ações textuais que decidem a superfície usam `default`: header de Page e footer de Page, Dialog
|
|
23
23
|
ou Drawer;
|
|
24
|
-
- ações operacionais em toolbar, header de seção ou coleção densa usam `sm`;
|
|
24
|
+
- ações operacionais em toolbar, header de seção ou coleção densa usam `sm`; a criação no header
|
|
25
|
+
de uma coleção é a exceção e usa `default` (ADR 0016);
|
|
25
26
|
- ações internas de linha, célula ou campo usam `xs` ou `icon-xs`;
|
|
26
|
-
- ações somente com ícone que pertencem ao chrome da superfície, como voltar
|
|
27
|
-
`icon
|
|
27
|
+
- ações somente com ícone que pertencem ao chrome da superfície, como voltar, usam `icon`; desde a
|
|
28
|
+
18.1.0 o fechamento de Dialog e Drawer é o `CloseButton`, em `icon-sm` por padrão (`closeSize`);
|
|
28
29
|
- `lg` fica reservado a chamadas que deliberadamente precisam de uma área de toque maior, não a
|
|
29
30
|
uma ação primária comum.
|
|
30
31
|
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
# ADR
|
|
1
|
+
# ADR 0018 — O cabeçalho modal apenas nomeia a superfície
|
|
2
|
+
|
|
3
|
+
> Publicada originalmente com o número 0012, que colidia com a ADR de Produtos de Dados do mesmo
|
|
4
|
+
> dia. Renumerada em 2026-09-16; o conteúdo não mudou.
|
|
2
5
|
|
|
3
6
|
- **Status:** aceita.
|
|
4
7
|
- **Data:** 2026-09-11.
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
# ADR
|
|
1
|
+
# ADR 0019 — Superfícies produtivas usam densidade compacta
|
|
2
|
+
|
|
3
|
+
> Publicada originalmente com o número 0016, que colidia com a ADR do cabeçalho da coleção.
|
|
4
|
+
> Renumerada em 2026-09-16; o conteúdo não mudou.
|
|
2
5
|
|
|
3
6
|
- **Status:** aceita.
|
|
4
7
|
- **Data:** 2026-09-14.
|
package/docs/code-style.md
CHANGED
|
@@ -98,8 +98,8 @@ Base instalada é dona do catálogo, dos kinds aceitos e do fundamento de cada r
|
|
|
98
98
|
| `Select.options[].hint/triggerLabel/group` | `label`, `label`, `heading` |
|
|
99
99
|
| `ActionTrigger.confirm.*` | papel correspondente do diálogo |
|
|
100
100
|
| `t.dict` — `label`, `description`, `doc` das entradas e `doc` do dicionário | `label`, `description` |
|
|
101
|
-
| `DataState`/`PageState`/`ActionList`/`ActionListDialog` — `emptyMessage`, `errorMessage`, `retryLabel`; `PageState
|
|
102
|
-
| `dialog.alert/confirm/prompt/choose()` — `title`, `
|
|
101
|
+
| `DataState`/`PageState`/`ActionList`/`ActionListDialog` — `emptyMessage`, `errorMessage`, `retryLabel`; `PageState` — `title`, `description`; `ActionListDialog` — `title`, `intro`; `ActionView.emptyMessage` | `empty-state`, `error`, `button`, `title`, `description` |
|
|
102
|
+
| `dialog.alert/confirm/prompt/choose()` — `title`, `body`, `action`, `cancel`, `placeholder`, `actions[].label` | papel correspondente do diálogo |
|
|
103
103
|
| `TooltipContent` (children), `LabelHelp.help` | `label`, `helper-text` |
|
|
104
104
|
|
|
105
105
|
## Cobertura e significado do gate verde
|
|
@@ -52,6 +52,6 @@ Há três sinais diferentes e eles não devem ser confundidos:
|
|
|
52
52
|
|
|
53
53
|
## Verificação
|
|
54
54
|
|
|
55
|
-
- o status do Maestro deve distinguir versão
|
|
55
|
+
- o status do Maestro deve distinguir versão disponível, adotada e aplicada;
|
|
56
56
|
- fixtures com tokens removidos devem reprovar no detector de migração, enquanto texto de
|
|
57
57
|
documentação e dependências geradas são ignorados.
|
package/docs/data-products.md
CHANGED
|
@@ -58,9 +58,11 @@ consumidores usam o nome qualificado; o alias só poderá ser removido numa vers
|
|
|
58
58
|
## Projeções
|
|
59
59
|
|
|
60
60
|
`opus gen` publica os produtos no `.opus/manifest.json`. Actions expostas como tools carregam os
|
|
61
|
-
IDs em `metadata.dataProducts
|
|
62
|
-
`_meta['com.softize.opus/data-products']
|
|
63
|
-
|
|
61
|
+
IDs em `metadata.dataProducts` e os rótulos legíveis em `metadata.dataProductLabels`, um mapa de ID
|
|
62
|
+
para `label`. No MCP, as chaves são `_meta['com.softize.opus/data-products']` e
|
|
63
|
+
`_meta['com.softize.opus/data-product-labels']`. Hosts mostram o rótulo às pessoas e usam o ID na
|
|
64
|
+
execução e na auditoria. Consumidores devem registrar apenas produtos associados a chamadas
|
|
65
|
+
concluídas com sucesso.
|
|
64
66
|
|
|
65
67
|
O Opus Lens usa o manifest para mostrar a linhagem declarada entre Fontes, entities, produtos e
|
|
66
68
|
Actions. Nenhuma dessas projeções é fonte autoritativa: corrija a declaração e gere novamente.
|
package/docs/protocol.md
CHANGED
|
@@ -604,7 +604,7 @@ Não vai ter `compose(authA, authB)` no core. Se sentir falta, é regra de negó
|
|
|
604
604
|
|
|
605
605
|
O Opus **não autentica** — não valida token, não emite sessão. O adapter (server) recebe a request, valida o token via auth provider externo (Better Auth, Clerk, próprio), monta `ctx.user`, e entrega pro Opus. A partir daí, `authorize` decide.
|
|
606
606
|
|
|
607
|
-
Se `ctx.user` é `null` e `public !== true`, runtime rejeita com `{ code: 'auth.unauthenticated', category: 'authentication' }` **antes** de
|
|
607
|
+
Se `ctx.user` é `null` e `public !== true`, runtime rejeita com `{ code: 'auth.unauthenticated', category: 'authentication' }` **antes** dos loaders e de `authorize`. Assim um chamador anônimo não dispara consultas nem descobre, pelo erro de um loader, se um registro existe.
|
|
608
608
|
|
|
609
609
|
---
|
|
610
610
|
|
|
@@ -1186,9 +1186,9 @@ ctx = { user, tenantId, can, db, emit, meta, ... }
|
|
|
1186
1186
|
↓
|
|
1187
1187
|
Runtime.execute(action, input, ctx)
|
|
1188
1188
|
↓ (1) validate input contra schema
|
|
1189
|
-
↓ (2)
|
|
1190
|
-
↓ (3)
|
|
1191
|
-
↓ (4) authorize (chama action.authorize)
|
|
1189
|
+
↓ (2) check public OR authenticate (ctx.user != null)
|
|
1190
|
+
↓ (3) load (se action declara `loads`)
|
|
1191
|
+
↓ (4) authorize (chama action.authorize, que pode usar o que foi carregado)
|
|
1192
1192
|
↓ (5) handler executa
|
|
1193
1193
|
(durante: handler pode chamar ctx.emit(event, data)
|
|
1194
1194
|
→ runtime publica via EventBusAdapter)
|
|
@@ -1426,14 +1426,14 @@ type BackgroundResult<T> =
|
|
|
1426
1426
|
```
|
|
1427
1427
|
HTTP request → Server adapter
|
|
1428
1428
|
↓ (1) validate input
|
|
1429
|
-
↓ (2)
|
|
1429
|
+
↓ (2) authenticate + load + authorize
|
|
1430
1430
|
↓ (3) enqueue job via QueueAdapter + audit do enqueue
|
|
1431
1431
|
↓
|
|
1432
1432
|
Server retorna JobHandle síncrono → client polla ou subscribe
|
|
1433
1433
|
↓
|
|
1434
1434
|
Worker (processo separado) consome job:
|
|
1435
1435
|
↓ (a) reidrata auth/can e chama runtime.executeJob(spec, ctx, progress)
|
|
1436
|
-
↓ (b) revalida input +
|
|
1436
|
+
↓ (b) revalida input + authenticate + load + authorize
|
|
1437
1437
|
↓ (c) handler (recebe ProgressReporter se config.progress)
|
|
1438
1438
|
↓ (d) validate output + audit com provenance background
|
|
1439
1439
|
↓ (e) processor retorna/lança; BullMQ atualiza status done/failed
|
package/docs/releasing.md
CHANGED
|
@@ -13,6 +13,13 @@ configuração de escopo ou token de leitura.
|
|
|
13
13
|
|
|
14
14
|
## Release pela estação (o caminho normal)
|
|
15
15
|
|
|
16
|
+
Antes de rodar, escreva no `CHANGELOG.md` a entrada `## X.Y.Z` da versão que vai sair. O script
|
|
17
|
+
confere essa entrada só DEPOIS do bump, então esquecê-la aborta a release com o `package.json` já
|
|
18
|
+
alterado — e a tentativa seguinte para na guarda de árvore limpa. Para recuperar, desfaça o bump
|
|
19
|
+
(`git checkout -- package.json`), escreva a entrada, commite e rode de novo.
|
|
20
|
+
|
|
21
|
+
Os comandos rodam em `packages/opus`; o `package.json` da raiz não tem `release`.
|
|
22
|
+
|
|
16
23
|
```bash
|
|
17
24
|
pnpm release # patch bump + publica no npm público
|
|
18
25
|
pnpm release minor # minor
|
|
@@ -53,7 +60,7 @@ pra testar publicação seria a guarda atrapalhando quem está experimentando.
|
|
|
53
60
|
|
|
54
61
|
**Gate de qualidade**: depois do bump e da materialização, mas antes de publicar, roda
|
|
55
62
|
`pnpm typecheck` + `pnpm test` + `pnpm copy:check` + `base copy check` e **aborta a release
|
|
56
|
-
se qualquer um falhar**. O Opus declara `@softize/base ^2.
|
|
63
|
+
se qualquer um falhar**. O Opus declara `@softize/base ^2.3.0` em `dependencies`, pois usa
|
|
57
64
|
suas APIs públicas de filesystem em runtime, e materializa os artefatos Base no próprio repo;
|
|
58
65
|
a release não baixa uma política ad hoc. Como o
|
|
59
66
|
Opus **ship source** (`.ts`, sem build), essa é a última barreira antes do tarball — sem ela,
|
|
@@ -67,7 +74,7 @@ não é bloqueada por cobertura abaixo de 100%; a cobertura é acompanhada com `
|
|
|
67
74
|
**Smoke do esqueleto**: depois do bump e antes do publish, o `release.sh` gera um app com
|
|
68
75
|
`opus create`, instala o **tarball exato** que vai ser publicado e roda os gates dele
|
|
69
76
|
(typecheck · test · `opus check` · `opus copy --check` · `base copy check` · manifest ·
|
|
70
|
-
build). O template exige `@softize/base ^2.
|
|
77
|
+
build). O template exige `@softize/base ^2.3.0`; publique a Base compatível antes do Opus.
|
|
71
78
|
O `minimumReleaseAgeExclude` do template inclui os dois pacotes, e o smoke executa os
|
|
72
79
|
fragmentos de pre-push para provar que o layout pnpm instalado resolve ambos os CLIs.
|
|
73
80
|
É o que pega o que typecheck+test não
|
|
@@ -80,7 +87,24 @@ O script bumpa, publica **e leva o bump pra `origin/main`** — não sobra passo
|
|
|
80
87
|
`--local` ele não commita nada (Verdaccio é sandbox). `pnpm release none` não cria diff de
|
|
81
88
|
versão, mas ainda commita qualquer derivado que a materialização legitimamente atualizar.
|
|
82
89
|
`--dry-run` encerra depois das mesmas materializações/gates/smoke, sem publish, commit ou
|
|
83
|
-
push; use `none` para validar a versão atual sem sujar o manifesto.
|
|
90
|
+
push; use `none` para validar a versão atual sem sujar o manifesto. Sem `--local`, o
|
|
91
|
+
`--dry-run` também exige a `main` limpa e igual a `origin/main`.
|
|
92
|
+
|
|
93
|
+
## A documentação é publicada à parte
|
|
94
|
+
|
|
95
|
+
A release publica o pacote, não o site. `opus.softize.com.br` só muda quando alguém roda, na raiz
|
|
96
|
+
do repositório:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pnpm deploy:docs
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
O script aplica as mesmas guardas de procedência da release, roda `typecheck`, `test`,
|
|
103
|
+
`copy:check` e o `opus check` de `apps/opus`, builda o site e envia o resultado. Ele não roda o
|
|
104
|
+
`base copy check` nem o smoke do esqueleto, que ficam com a release. Rode-o depois de cada
|
|
105
|
+
release; sem isso, o site continua mostrando a versão anterior.
|
|
106
|
+
Em setembro de 2026, o site ficou onze dias preso numa versão anterior à 13.0.0 enquanto o
|
|
107
|
+
pacote chegava à 18.1.0. `pnpm deploy:docs --dry-run` valida sem enviar.
|
|
84
108
|
|
|
85
109
|
## Verificar
|
|
86
110
|
|
|
@@ -111,7 +135,7 @@ pnpm add @softize/opus@8.7.0-rc.0 --registry http://127.0.0.1:6873/
|
|
|
111
135
|
|
|
112
136
|
Valide o app normalmente. Ao encerrar a sessão, restaure o intervalo de versão do
|
|
113
137
|
consumidor para o npm e rode `pnpm install`; a prerelease local nunca é enviada ao npm.
|
|
114
|
-
Para publicar outra tentativa, incremente o
|
|
138
|
+
Para publicar outra tentativa, incremente o sufixo (`8.7.0-rc.1`, por exemplo) e repita
|
|
115
139
|
o mesmo fluxo.
|
|
116
140
|
|
|
117
141
|
## Auth
|
package/package.json
CHANGED
|
@@ -73,6 +73,11 @@ ContentDescription, ContentMeta, ContentActions) + ContentBody`. `ContentHeader`
|
|
|
73
73
|
- `ActionFilterBar` renderiza busca, filtros, período e ações declarados por uma list action
|
|
74
74
|
quando a tela precisa da toolbar sem entregar os resultados a `ActionList`. Manter seu
|
|
75
75
|
`state` e `onStateChange` ligados à mesma projeção de URL usada pela superfície.
|
|
76
|
+
- Filtros de list action declaram onde aparecem com `placement`: `inline` fica na barra;
|
|
77
|
+
`advanced` vai para o painel de filtros avançados, agrupado por `section` e distribuído em até
|
|
78
|
+
três colunas com `advancedFilters.columns`; `external` continua no estado navegável e no input,
|
|
79
|
+
mas a tela apresenta o controle por conta própria. `advanced: true` segue aceito só durante a
|
|
80
|
+
migração; em código novo, declarar `placement`.
|
|
76
81
|
- `ActionForm` mantém validação, execução e estados do contrato nos dois modos: sem `children`,
|
|
77
82
|
renderiza os campos declarados; com `children`, o consumidor diagrama `ActionFormField` e
|
|
78
83
|
controles customizados pelo contexto. `ActionFormCard` e `ActionFormDialog` acrescentam a
|
|
@@ -81,8 +86,13 @@ ContentDescription, ContentMeta, ContentActions) + ContentBody`. `ContentHeader`
|
|
|
81
86
|
a ação principal mantém `solid`. Criação e edição comuns preservam o rótulo padrão `Salvar`;
|
|
82
87
|
`submitLabel` fica para efeitos específicos, como `Renomear` ou `Criar nova versão`. Em
|
|
83
88
|
`Dialog mode="alert"`, a saída segura também usa `outline`.
|
|
89
|
+
- `DialogFooter` e `DrawerFooter` cuidam só da faixa. Agrupar e distribuir as decisões cabe a um
|
|
90
|
+
`ButtonGroup` dentro deles, com `distribution="equal"` para o footer 50/50; botões soltos no
|
|
91
|
+
footer não são distribuídos. `ActionFormDialog` já compõe isso: por padrão o footer acompanha o
|
|
92
|
+
conteúdo com o cancelamento em `ghost`, e `footerDistribution="equal"` divide a faixa e passa o
|
|
93
|
+
cancelamento a `outline`.
|
|
84
94
|
- Cabeçalhos de `Dialog` e `Drawer` nomeiam a superfície com o título e organizam suas ações. O close
|
|
85
|
-
padrão é
|
|
95
|
+
padrão é o `CloseButton` (`neutral`, `subtle`, pílula) no final do header, sem posição flutuante
|
|
86
96
|
alternativa. Não preencher uma segunda linha por hábito. Consequência, restrição ou instrução que
|
|
87
97
|
realmente mude a tarefa entra no início de `DialogBody`/`DrawerBody`, como texto ou `Alert`;
|
|
88
98
|
wrappers usam `intro` e a API imperativa usa `body`. Relacione texto conciso por
|
package/src/auth/drivers/jwt.ts
CHANGED
|
@@ -34,7 +34,8 @@ import type { AuthAdapter, CanFn, User } from '../../core/index.ts'
|
|
|
34
34
|
// =============================================================================
|
|
35
35
|
|
|
36
36
|
export interface JwtAuthOptions<P extends JwtPayload = JwtPayload> {
|
|
37
|
-
/** Secret HMAC ou public key
|
|
37
|
+
/** Secret HMAC ou public key, fixo ou por resolver (sync ou async). O resolver é chamado
|
|
38
|
+
* sem argumentos: a escolha da chave pelo `kid` do token ainda não é suportada. */
|
|
38
39
|
secret: string | Buffer | ((kid?: string) => Promise<string | Buffer> | string | Buffer)
|
|
39
40
|
|
|
40
41
|
/** Algorithms aceitos (default ['HS256']). */
|