@softize/opus 11.0.0 → 11.1.1
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 +24 -0
- package/bin/cli.mjs +1 -1
- package/bin/lib/init.mjs +6 -0
- package/bin/lib/materialize.mjs +3 -1
- package/package.json +1 -1
- package/registry/instructions/opus.md +3 -0
- package/registry/skills/build-opus-ui/SKILL.md +2 -0
- package/registry/skills/create-opus-action/SKILL.md +2 -0
- package/registry/skills/implement-opus-change/SKILL.md +2 -0
- package/registry/skills/upgrade-opus/SKILL.md +2 -0
- package/registry/skills/write-product-communication/SKILL.md +28 -0
- package/registry/skills/write-product-communication/agents/openai.yaml +4 -0
- package/src/data/readonly-pool.ts +2 -2
- package/src/ui/docs/DocBrowser.tsx +10 -2
- package/src/ui/docs/content/actions.md +7 -6
- package/src/ui/docs/content/auth.md +3 -2
- package/src/ui/docs/content/cli.md +2 -1
- package/src/ui/docs/content/communication.md +130 -0
- package/src/ui/docs/content/data.md +1 -1
- package/src/ui/docs/content/getting-started.md +15 -23
- package/src/ui/docs/content/upgrading.md +1 -1
- package/src/ui/docs/registry.tsx +2 -2
- package/src/ui/docs/content/microcopy.md +0 -83
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,30 @@ Este arquivo viaja no pacote: num projeto, leia `node_modules/@softize/opus/CHAN
|
|
|
6
6
|
Depois de qualquer bump, rode os gates (`typecheck` · `test` · `opus check` ·
|
|
7
7
|
`manifest:check`) — eles apontam o que a mudança cobra do seu código.
|
|
8
8
|
|
|
9
|
+
## 11.1.1 — 2026-08-21
|
|
10
|
+
|
|
11
|
+
A referência canônica passa a usar `communication.md` como nome do arquivo e `communication`
|
|
12
|
+
como slug. Assim, o nome interno e a URL acompanham o escopo ampliado da página, que deixou de
|
|
13
|
+
tratar apenas de microcopy. A URL anterior, `/ui/microcopy`, redireciona para
|
|
14
|
+
`/ui/communication`, preservando links existentes sem manter o nome antigo na navegação ou na
|
|
15
|
+
fonte materializada.
|
|
16
|
+
|
|
17
|
+
## 11.1.0 — 2026-08-21
|
|
18
|
+
|
|
19
|
+
O Opus passa a distribuir a skill `write-product-communication` para orientar documentação,
|
|
20
|
+
interface, mensagens de erro, CLI, onboarding e textos explicativos a partir da situação do
|
|
21
|
+
leitor. A página antes dedicada apenas a microcopy agora reúne a referência canônica de
|
|
22
|
+
comunicação, incluindo escrita normativa e tratamento de erros.
|
|
23
|
+
|
|
24
|
+
O `opus setup` expande o conteúdo dessa referência ao materializar a skill em `.agents` e
|
|
25
|
+
`.claude`. As instruções permanentes e as skills de UI, actions, mudanças e upgrades passam a
|
|
26
|
+
acionar a orientação nos fluxos em que produzem texto. Testes de criação e setup confirmam que
|
|
27
|
+
projetos novos recebem o conteúdo completo, sem depender de um link externo.
|
|
28
|
+
|
|
29
|
+
A home, as páginas iniciais e a mensagem de sucesso do `opus check` começam a migração da voz
|
|
30
|
+
existente: apresentam contexto e efeito antes das regras, evitam slogans e informam a próxima
|
|
31
|
+
etapa em linguagem natural.
|
|
32
|
+
|
|
9
33
|
> As entradas 2.30.1–2.31.5 foram **reconstruídas do git** (o release publicava sem
|
|
10
34
|
> passar por aqui). Uma delas — a 2.31.5, que mudou o rem base — é visual GLOBAL e
|
|
11
35
|
> tinha ficado sem registro nenhum, o que é exatamente o caso que este arquivo existe
|
package/bin/cli.mjs
CHANGED
|
@@ -190,7 +190,7 @@ async function cmdCheck(dir) {
|
|
|
190
190
|
}
|
|
191
191
|
const viaContrato = contracts > 0 ? ` (${contracts} contrato(s))` : ''
|
|
192
192
|
if (findings.length === 0) {
|
|
193
|
-
log('success', `✓ opus check: ${actions} action(s)${viaContrato}
|
|
193
|
+
log('success', `✓ opus check: ${actions} action(s)${viaContrato}; nenhuma violação encontrada.`)
|
|
194
194
|
return
|
|
195
195
|
}
|
|
196
196
|
|
package/bin/lib/init.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** opus setup: aplica o marcador per-app e os artefatos Opus rastreáveis no repo. */
|
|
2
2
|
|
|
3
3
|
import { promises as fs } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
|
|
6
7
|
import { materializeOpus, PACKAGE_VERSION } from "./materialize.mjs";
|
|
@@ -27,7 +28,12 @@ async function readJson(p) {
|
|
|
27
28
|
/** Raiz do repo (sobe até achar `.git`); sem repo → null (o chamador decide o fallback). */
|
|
28
29
|
export async function repoRootOf(dir) {
|
|
29
30
|
let cur = path.resolve(dir);
|
|
31
|
+
const temporaryRoot = path.resolve(tmpdir());
|
|
30
32
|
for (;;) {
|
|
33
|
+
// O diretório temporário global pode receber marcadores transitórios de ferramentas
|
|
34
|
+
// e sandboxes. Um projeto dentro dele ainda pode ter sua própria raiz Git, mas não deve
|
|
35
|
+
// herdar `/tmp/.git` como se todos os fixtures pertencessem ao mesmo repositório.
|
|
36
|
+
if (cur === temporaryRoot) return null;
|
|
31
37
|
if (await exists(path.join(cur, ".git"))) return cur;
|
|
32
38
|
const up = path.dirname(cur);
|
|
33
39
|
if (up === cur) return null;
|
package/bin/lib/materialize.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, extname, join, relative, resolve } from 'node:path'
|
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
7
7
|
import { validateSkill } from './validate-skill.mjs'
|
|
8
|
+
import { expandDocIncludes } from './docs-include.mjs'
|
|
8
9
|
|
|
9
10
|
export const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
|
|
10
11
|
export const PACKAGE_NAME = '@softize/opus'
|
|
@@ -97,7 +98,8 @@ function expectedFiles(exclude) {
|
|
|
97
98
|
for (const file of filesUnder(join(PACKAGE_ROOT, sourceRoot))) {
|
|
98
99
|
const source = `${sourceRoot}/${file.relative}`
|
|
99
100
|
const destination = `${destinationRoot}/${file.relative}`
|
|
100
|
-
const
|
|
101
|
+
const sourceContent = readFileSync(file.path, 'utf8')
|
|
102
|
+
const content = file.relative === 'SKILL.md' ? expandDocIncludes(sourceContent) : sourceContent
|
|
101
103
|
expected.set(destination, { source, content, output: addMarker(destination, source, content) })
|
|
102
104
|
}
|
|
103
105
|
}
|
package/package.json
CHANGED
|
@@ -15,3 +15,6 @@ artefatos de agentes fica em `base.json`; cada app Opus mantém seu marcador `op
|
|
|
15
15
|
branch antes de commit/review e usar `upgrade-opus` para ler changelog e aplicar migrações.
|
|
16
16
|
- Consultar as skills Opus materializadas conforme o workflow; não atribuir ao SDK decisões
|
|
17
17
|
universais de domínio ou arquitetura.
|
|
18
|
+
- Usar `write-product-communication` ao criar ou alterar documentação, textos de interface,
|
|
19
|
+
mensagens de erro, CLI, onboarding ou explicações. Partir da situação do leitor, apresentar
|
|
20
|
+
contexto antes da regra e evitar slogans, absolutos e linguagem de manifesto.
|
|
@@ -26,6 +26,8 @@ existentes, mantendo navegação observável e componentes reutilizáveis sem la
|
|
|
26
26
|
7. Usar diretamente a escala `rounded-*`; não criar radius por nome de componente quando
|
|
27
27
|
`rounded-sm` a `rounded-xl` já expressam a forma.
|
|
28
28
|
8. Testar estados de loading, vazio, erro, sucesso, permissão e interação relevante.
|
|
29
|
+
9. Usar `write-product-communication` para labels, ajuda, estados vazios, confirmações e erros;
|
|
30
|
+
revisar o fluxo completo, não apenas cada string isolada.
|
|
29
31
|
|
|
30
32
|
## Verificação
|
|
31
33
|
|
|
@@ -21,6 +21,8 @@ registrados no runtime do projeto.
|
|
|
21
21
|
1. Rodar `node scripts/scaffold.mjs <resource> <verb> <kind>` a partir desta skill.
|
|
22
22
|
2. Colocar o contrato em módulo importável pelos consumidores e o binding no lado servidor.
|
|
23
23
|
3. Substituir os exemplos do scaffold por schemas, descrições e comportamento do domínio.
|
|
24
|
+
Usar `write-product-communication` nas descrições, mensagens e textos projetados para UI
|
|
25
|
+
ou documentação.
|
|
24
26
|
4. Declarar `requires` somente com `authorize` efetivo; `requires` sozinho não protege a action.
|
|
25
27
|
5. Exportar e registrar o binding no domínio/runtime existente.
|
|
26
28
|
6. Acionar `test-opus-action` para cobrir contrato, sucesso, erros e efeitos relevantes.
|
|
@@ -25,6 +25,8 @@ dependências server-only, bindings registrados, testes e gates verdes.
|
|
|
25
25
|
5. Usar `create-opus-action`, `test-opus-action` ou `build-opus-ui` quando a mudança entrar
|
|
26
26
|
nesses workflows especializados.
|
|
27
27
|
6. Atualizar manifest, docs geradas e exemplos somente pelos comandos do repo.
|
|
28
|
+
7. Usar `write-product-communication` sempre que a mudança alcançar documentação, UI, CLI,
|
|
29
|
+
mensagens de erro ou outro texto destinado a uma pessoa.
|
|
28
30
|
|
|
29
31
|
## Verificação
|
|
30
32
|
|
|
@@ -19,6 +19,8 @@ materializados e projeções geradas consistentes no mesmo diff.
|
|
|
19
19
|
4. Aplicar migrações no código por domínio, sem compatibilidade temporária silenciosa.
|
|
20
20
|
5. Rodar `opus check`, typecheck, testes, build e geradores declarados pelo projeto.
|
|
21
21
|
6. Conferir `base.json`, lockfile, skills, hooks, instruções e outputs gerados no diff.
|
|
22
|
+
7. Usar `write-product-communication` ao redigir changelog, guia de migração e mensagens
|
|
23
|
+
adicionadas ou alteradas durante o upgrade.
|
|
22
24
|
|
|
23
25
|
## Verificação
|
|
24
26
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-product-communication
|
|
3
|
+
description: Escreve e revisa comunicação de produto clara, humana e orientada ao leitor. Usar ao criar ou alterar documentação, mensagens de erro, textos de interface, CLI, onboarding, ajuda, explicações, comentários ou qualquer conteúdo que uma pessoa precise compreender.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Escrever comunicação de produto
|
|
7
|
+
|
|
8
|
+
## Resultado
|
|
9
|
+
|
|
10
|
+
Entregar uma comunicação que parte da situação do leitor, oferece o contexto necessário e
|
|
11
|
+
permite que a pessoa compreenda ou prossiga sem decodificar a linguagem interna da equipe.
|
|
12
|
+
|
|
13
|
+
## Procedimento
|
|
14
|
+
|
|
15
|
+
1. Identificar quem lerá o texto, o que essa pessoa tenta fazer e o que precisa compreender ou
|
|
16
|
+
decidir em seguida.
|
|
17
|
+
2. Ler a comunicação no fluxo completo em que aparecerá, incluindo estados anteriores e
|
|
18
|
+
posteriores.
|
|
19
|
+
3. Escrever a partir do problema e do efeito percebido; introduzir mecanismos e termos técnicos
|
|
20
|
+
somente quando acrescentarem precisão.
|
|
21
|
+
4. Distinguir princípios, regras, recomendações, comportamentos, verificações e exceções.
|
|
22
|
+
5. Revisar o texto fora do contexto da implementação e remover pressupostos, slogans,
|
|
23
|
+
advertências desnecessárias e detalhes internos.
|
|
24
|
+
6. Confirmar que erros explicam o ocorrido, o impacto e uma próxima ação real quando ela existir.
|
|
25
|
+
|
|
26
|
+
## Referência canônica
|
|
27
|
+
|
|
28
|
+
<!-- opus-doc: communication.md -->
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 1. **Pool com teto** — crie o `Pool` com `max` (e/ou use `maxConcurrent` aqui):
|
|
7
7
|
* query de LLM não esgota as conexões do app.
|
|
8
|
-
* 2. **Transação READ ONLY** — `BEGIN TRANSACTION READ ONLY`:
|
|
9
|
-
*
|
|
8
|
+
* 2. **Transação READ ONLY** — `BEGIN TRANSACTION READ ONLY`: o servidor rejeita
|
|
9
|
+
* qualquer tentativa de escrita, independentemente do SQL recebido.
|
|
10
10
|
* 3. **`SET LOCAL ROLE` por transação** — o alcance é do contexto: com grants
|
|
11
11
|
* default-fechado, `sales_read` não enxerga `hr_employees.salary` nem por
|
|
12
12
|
* SELECT criativo. (Criar os roles/grants é migração sua; aqui só se assume.)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DocBrowser — a VERDADE VISUAL da casa, como doc completa. Seção multi-página: conceitos
|
|
3
|
-
* (Introdução, Tokens & Tema,
|
|
3
|
+
* (Introdução, Tokens & Tema, Comunicação, Customização) + uma página por componente do
|
|
4
4
|
* opus/ui, agrupados por seção. O que você vê aqui é o que os apps entregam (o site
|
|
5
5
|
* do shadcn é catálogo do que existe; a expectativa visual nasce aqui).
|
|
6
6
|
*
|
|
@@ -35,6 +35,8 @@ export interface DocBrowserProps {
|
|
|
35
35
|
path?: string
|
|
36
36
|
/** Seções a exibir (seção → grupo → página). Default = catálogo inteiro. */
|
|
37
37
|
sections?: DocSection[]
|
|
38
|
+
/** Slugs antigos que devem abrir e substituir a URL pela página canônica. */
|
|
39
|
+
redirects?: Readonly<Record<string, string>>
|
|
38
40
|
/** Monta o `document.title` a partir do título da página atual (ex.: `(t) => `${t} · Opus``).
|
|
39
41
|
* Ausente = não mexe no title. */
|
|
40
42
|
documentTitle?: (pageTitle: string) => string
|
|
@@ -44,6 +46,7 @@ export function DocBrowser({
|
|
|
44
46
|
basePath = '/docs',
|
|
45
47
|
path: controlledPath,
|
|
46
48
|
sections = DOC_SECTIONS,
|
|
49
|
+
redirects = {},
|
|
47
50
|
documentTitle,
|
|
48
51
|
}: DocBrowserProps): React.ReactElement {
|
|
49
52
|
// Standalone: o path vem do router da casa (`usePathname` — pathname É o estado).
|
|
@@ -56,13 +59,18 @@ export function DocBrowser({
|
|
|
56
59
|
// Slug = TODOS os segmentos após o basePath, unidos (rota aninhada: `/docs/guias/deploy`
|
|
57
60
|
// → `guias/deploy`). Slug flat de 1 segmento continua igual (`join` de 1 elemento = ele).
|
|
58
61
|
const rel = path.startsWith(basePath) ? path.slice(basePath.length) : ''
|
|
59
|
-
const
|
|
62
|
+
const requestedSlug = rel.split('/').filter(Boolean).join('/') || defaultSlug
|
|
63
|
+
const slug = redirects[requestedSlug] ?? requestedSlug
|
|
60
64
|
const page = findPage(sections, slug) ?? findPage(sections, defaultSlug)
|
|
61
65
|
|
|
62
66
|
// `navigate` emite `popstate`, então o host é notificado nos dois modos — inclusive o
|
|
63
67
|
// que ainda escuta o evento na unha, que era como este componente avisava antes.
|
|
64
68
|
const go = (to: string): void => navigate(to)
|
|
65
69
|
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (requestedSlug !== slug) navigate(`${basePath}/${slug}`, { replace: true })
|
|
72
|
+
}, [basePath, requestedSlug, slug])
|
|
73
|
+
|
|
66
74
|
// O title da aba acompanha a página atual (quando o host fornece o formato).
|
|
67
75
|
useEffect(() => {
|
|
68
76
|
if (page && documentTitle) document.title = documentTitle(page.title)
|
|
@@ -4,9 +4,9 @@ title: Actions & contratos
|
|
|
4
4
|
|
|
5
5
|
# Actions & contratos
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
Uma action descreve uma operação que cliente e servidor precisam compreender da mesma forma.
|
|
8
|
+
Seu contrato reúne entidade, entrada, saída e metadados no package compartilhado. A API conecta
|
|
9
|
+
o handler e a web usa a mesma definição para executar ou renderizar a operação.
|
|
10
10
|
|
|
11
11
|
## Contrato primeiro
|
|
12
12
|
|
|
@@ -51,8 +51,9 @@ export const workspaceCreate = bindAction(workspaceCreateContract, {
|
|
|
51
51
|
|
|
52
52
|
## Ordem canônica dos campos
|
|
53
53
|
|
|
54
|
-
>
|
|
55
|
-
> `create-opus-action`
|
|
54
|
+
> Esta ordem mantém contratos previsíveis para leitura e geração. O `opus check` informa os
|
|
55
|
+
> campos que precisam ser reposicionados, e a skill `create-opus-action` já cria o contrato e o
|
|
56
|
+
> binding nessa estrutura.
|
|
56
57
|
|
|
57
58
|
```text
|
|
58
59
|
name → kind → (label / summary / messages / tags…)
|
|
@@ -130,7 +131,7 @@ descartável — vira o contrato que o backend honra.
|
|
|
130
131
|
import { useLookupAction } from '@softize/opus/client'
|
|
131
132
|
import { ActionForm } from '@softize/opus/ui/react'
|
|
132
133
|
|
|
133
|
-
//
|
|
134
|
+
// O contrato mantém a lista paginada tipada sem exigir uma definição paralela.
|
|
134
135
|
const { rows, fetchNextPage } = useLookupAction(workspaceListContract)
|
|
135
136
|
|
|
136
137
|
// Form contract-driven: os campos (fields) moram NO contrato.
|
|
@@ -21,8 +21,9 @@ interface AuthAdapter {
|
|
|
21
21
|
}
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
`req` é o request cru do `ServerAdapter`. O `user`
|
|
25
|
-
|
|
24
|
+
`req` é o request cru do `ServerAdapter`. O `user` vem dos claims ou da sessão, e o driver
|
|
25
|
+
fornece a função `can` que decide cada autorização. O Opus chama essa função sem definir a
|
|
26
|
+
política usada por ela.
|
|
26
27
|
|
|
27
28
|
## Drivers
|
|
28
29
|
|
|
@@ -9,7 +9,8 @@ valida as convenções e expõe o estado vivo pros agentes via MCP.
|
|
|
9
9
|
|
|
10
10
|
## Gates
|
|
11
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
14
|
|
|
14
15
|
```bash
|
|
15
16
|
opus check src # valida as convenções das actions (exit ≠ 0 se violar)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Comunicação
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Comunicação
|
|
6
|
+
|
|
7
|
+
Toda comunicação do produto deve ajudar alguém a compreender o que está acontecendo e a
|
|
8
|
+
seguir adiante com confiança. Esta orientação vale para documentação, interfaces, mensagens
|
|
9
|
+
de erro, CLI, onboarding, textos explicativos, comentários e respostas produzidas por agentes.
|
|
10
|
+
|
|
11
|
+
Clareza não significa apenas escrever frases curtas. Um texto claro parte da situação do
|
|
12
|
+
leitor, apresenta o que ele precisa saber e oferece contexto suficiente para que a próxima
|
|
13
|
+
decisão não dependa de adivinhação.
|
|
14
|
+
|
|
15
|
+
## Antes de escrever
|
|
16
|
+
|
|
17
|
+
Identifique quem lerá o texto, o que essa pessoa está tentando fazer e qual decisão ou ação
|
|
18
|
+
deve ser possível depois da leitura. Quando essas respostas não estiverem claras, investigue o
|
|
19
|
+
fluxo antes de escolher as palavras.
|
|
20
|
+
|
|
21
|
+
Organize a explicação nesta ordem sempre que ela ajudar:
|
|
22
|
+
|
|
23
|
+
1. apresente a situação ou o problema reconhecível pelo leitor;
|
|
24
|
+
2. explique o benefício ou o efeito esperado;
|
|
25
|
+
3. descreva o mecanismo somente no nível necessário;
|
|
26
|
+
4. indique a próxima ação quando houver uma.
|
|
27
|
+
|
|
28
|
+
Não comece pela arquitetura interna quando a necessidade do leitor oferece uma introdução
|
|
29
|
+
mais natural. Termos técnicos são bem-vindos quando acrescentam precisão, mas devem ser
|
|
30
|
+
apresentados antes de serem usados como parte da explicação.
|
|
31
|
+
|
|
32
|
+
## Voz
|
|
33
|
+
|
|
34
|
+
Escreva de maneira calma, próxima e segura. A comunicação pode ser firme sem parecer uma
|
|
35
|
+
ordem interna ou um manifesto.
|
|
36
|
+
|
|
37
|
+
- Prefira explicações completas a slogans, máximas e frases de efeito.
|
|
38
|
+
- Evite absolutos como “sempre”, “nunca”, “zero” e “é” quando houver contexto, condição ou
|
|
39
|
+
exceção relevante.
|
|
40
|
+
- Não use caixa-alta, negrito ou pontuação para fabricar autoridade.
|
|
41
|
+
- Evite sequências telegráficas, equações e símbolos usados como conectores em prosa.
|
|
42
|
+
- Não presuma que o leitor já concorda com a arquitetura ou conhece o vocabulário da equipe.
|
|
43
|
+
- Explique decisões pelo valor que oferecem às pessoas, não apenas pela disciplina que impõem.
|
|
44
|
+
- Mantenha o mesmo termo para o mesmo conceito em todas as superfícies.
|
|
45
|
+
|
|
46
|
+
Em vez de “O domínio é a aplicação. Front e back são cascas”, explique a relação:
|
|
47
|
+
|
|
48
|
+
> O Opus mantém as regras e os contratos do domínio em uma camada compartilhada. Assim,
|
|
49
|
+
> cliente e servidor trabalham com as mesmas definições, sem duplicar schemas, validações ou
|
|
50
|
+
> tipos de transporte.
|
|
51
|
+
|
|
52
|
+
## Documentação
|
|
53
|
+
|
|
54
|
+
Uma documentação deve formar o modelo mental do leitor antes de cobrar decisões baseadas
|
|
55
|
+
nele. Apresente primeiro o problema, depois a ideia, um exemplo concreto e os próximos passos.
|
|
56
|
+
Detalhes operacionais e situações excepcionais devem ficar próximos da etapa em que se tornam
|
|
57
|
+
úteis, sem interromper a introdução principal.
|
|
58
|
+
|
|
59
|
+
Ao registrar uma norma, deixe claro o peso da afirmação:
|
|
60
|
+
|
|
61
|
+
- **Princípio:** explica a intenção que orienta as decisões.
|
|
62
|
+
- **Regra:** descreve um requisito obrigatório e seu escopo.
|
|
63
|
+
- **Recomendação:** apresenta o caminho preferido quando outras opções continuam válidas.
|
|
64
|
+
- **Comportamento:** informa o que o produto faz automaticamente.
|
|
65
|
+
- **Verificação:** mostra como confirmar que a regra foi atendida.
|
|
66
|
+
- **Exceção:** delimita quando a orientação não se aplica.
|
|
67
|
+
|
|
68
|
+
Uma regra normativa deve informar a condição em que se aplica, a razão que a sustenta e como
|
|
69
|
+
ela é verificada. Por exemplo:
|
|
70
|
+
|
|
71
|
+
> Cada action deve ser declarada em um arquivo próprio. Essa separação permite que o registro e
|
|
72
|
+
> os geradores identifiquem cada action de forma determinística. O `opus check` informa quais
|
|
73
|
+
> arquivos precisam ser separados quando encontra mais de uma declaração.
|
|
74
|
+
|
|
75
|
+
Evite substituir essa explicação por “Uma por arquivo. O gate reprova”. A versão curta omite o
|
|
76
|
+
motivo, não delimita o escopo e transforma uma ajuda em uma advertência.
|
|
77
|
+
|
|
78
|
+
## Mensagens de erro
|
|
79
|
+
|
|
80
|
+
Uma mensagem de erro deve responder, nessa ordem, ao que aconteceu, como isso afeta a tarefa e
|
|
81
|
+
o que a pessoa pode fazer. Não culpe o usuário e não exponha endpoint, stack trace, status HTTP
|
|
82
|
+
ou detalhes do runtime na interface; esses dados pertencem ao log ou à área de diagnóstico.
|
|
83
|
+
|
|
84
|
+
| Situação | Prefira | Evite |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| Serviço indisponível | O Multica não respondeu. Tente novamente em alguns instantes. | ERRO: request failed (500) |
|
|
87
|
+
| Recurso ausente | Este workspace não existe mais. Volte à lista para escolher outro. | Workspace inválido. |
|
|
88
|
+
| Permissão | Você não tem acesso a este workspace. Peça acesso a um administrador. | Acesso negado. |
|
|
89
|
+
| Validação | Informe um endereço de e-mail válido. | Campo inválido. |
|
|
90
|
+
|
|
91
|
+
Quando não houver uma ação possível, diga isso com honestidade e preserve o trabalho já feito.
|
|
92
|
+
Não ofereça “tente novamente” como resposta automática para falhas que uma nova tentativa não
|
|
93
|
+
pode resolver.
|
|
94
|
+
|
|
95
|
+
## Textos de interface
|
|
96
|
+
|
|
97
|
+
Código e valores internos permanecem em inglês. O que uma pessoa lê na interface usa pt-BR,
|
|
98
|
+
salvo quando o produto declarar outro idioma.
|
|
99
|
+
|
|
100
|
+
- Frases começam com maiúscula e terminam com ponto.
|
|
101
|
+
- Labels, títulos, itens de menu e botões usam sentence case e não levam ponto.
|
|
102
|
+
- Placeholders de seleção usam `Selecione <artigo> <coisa>…`.
|
|
103
|
+
- Placeholders ajudam a responder, mas não substituem o label do campo.
|
|
104
|
+
- Botões descrevem a ação que executarão, como `Publicar` ou `Salvar alterações`.
|
|
105
|
+
- Textos de ajuda explicam o efeito percebido, não a implementação interna.
|
|
106
|
+
- Abreviações são usadas somente quando o espaço ou o vocabulário do domínio as justificam.
|
|
107
|
+
|
|
108
|
+
| Tipo | Prefira | Evite |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| Frase | A configuração não carregou. | Config indisponível. |
|
|
111
|
+
| Label | Nova sessão | Nova sessão. |
|
|
112
|
+
| Botão | Publicar | PUBLICAR |
|
|
113
|
+
| Placeholder | Selecione um cliente… | Selecionar |
|
|
114
|
+
| Ajuda | Os agentes deste workspace passam a usar esta skill. | O push sobrescreve o runtime. |
|
|
115
|
+
|
|
116
|
+
## Revisão
|
|
117
|
+
|
|
118
|
+
Antes de entregar, releia o texto fora do contexto da implementação e confirme:
|
|
119
|
+
|
|
120
|
+
- o leitor consegue reconhecer a situação sem conhecer o código;
|
|
121
|
+
- conceitos novos são explicados antes de orientar decisões;
|
|
122
|
+
- regras obrigatórias estão separadas de recomendações;
|
|
123
|
+
- a razão da orientação aparece quando ajuda a compreendê-la;
|
|
124
|
+
- mensagens de erro preservam a calma e oferecem uma saída real;
|
|
125
|
+
- a frase soa como uma conversa profissional, não como log, slogan ou ordem interna;
|
|
126
|
+
- detalhes técnicos permanecem disponíveis no lugar adequado sem dominar a comunicação.
|
|
127
|
+
|
|
128
|
+
Leia o fluxo completo, não apenas strings isoladas. Um conjunto de frases corretas ainda pode
|
|
129
|
+
produzir uma experiência confusa quando repete informações, muda de vocabulário ou apresenta
|
|
130
|
+
ações fora da ordem em que a pessoa precisa delas.
|
|
@@ -88,7 +88,7 @@ const { rows } = await bi.query(sqlDoLlm, { role: roleFor(ctx) })
|
|
|
88
88
|
|
|
89
89
|
1. **Pool com teto** (`max` do pool e/ou `maxConcurrent`) — query de LLM não esgota as
|
|
90
90
|
conexões do app;
|
|
91
|
-
2. **`BEGIN TRANSACTION READ ONLY`** —
|
|
91
|
+
2. **`BEGIN TRANSACTION READ ONLY`** — o servidor rejeita tentativas de escrita;
|
|
92
92
|
3. **`SET LOCAL ROLE` por transação** — o alcance é do CONTEXTO (crie os roles com grants
|
|
93
93
|
default-fechado nas suas migrações: sem isso, `sales_read` leria `hr_employees`);
|
|
94
94
|
4. **Protocolo estendido** — o SQL roda sempre com array de valores; multi-sentença
|
|
@@ -4,42 +4,34 @@ title: Getting started
|
|
|
4
4
|
|
|
5
5
|
# Getting started
|
|
6
6
|
|
|
7
|
-
O Opus
|
|
8
|
-
|
|
7
|
+
O Opus ajuda cliente e servidor a preservar as mesmas regras à medida que uma aplicação
|
|
8
|
+
evolui. Entidades e contratos de action ficam em uma camada compartilhada; o runtime, a UI e
|
|
9
|
+
as ferramentas usam essas definições sem exigir schemas e tipos paralelos.
|
|
9
10
|
|
|
10
11
|
## O modelo
|
|
11
12
|
|
|
12
|
-
>
|
|
13
|
+
> Comece pelo problema que o modelo compartilhado resolve antes de conhecer seus arquivos.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
As regras de uma aplicação costumam aparecer em vários lugares: validação, transporte, API,
|
|
16
|
+
formulários e documentação. No Opus, entidades, dicts e contratos de action descrevem essas
|
|
17
|
+
regras uma vez. A API e a web consomem a mesma definição, enquanto runtime, adapters, UI, CLI
|
|
18
|
+
e verificações ajudam a mantê-la consistente. Cada projeto acrescenta seu domínio sobre essa
|
|
19
|
+
base versionada.
|
|
17
20
|
|
|
18
21
|
## Começar do zero
|
|
19
22
|
|
|
20
23
|
> Projeto novo não se monta à mão: o esqueleto canônico sai do `opus create`, com os
|
|
21
24
|
> pré-requisitos do protocolo, da UI e do preview já plugados — e os gates verdes.
|
|
22
25
|
|
|
23
|
-
O Opus mora no registry da Softize (não no npm público) — uma vez por máquina, ensine
|
|
24
|
-
o escopo ao pnpm; dentro do projeto criado o `.npmrc` já cuida disso:
|
|
25
|
-
|
|
26
26
|
```bash
|
|
27
|
-
pnpm config set @softize:registry https://registry.softize.com.br/ --global # 1x por máquina
|
|
28
|
-
|
|
29
27
|
pnpm dlx @softize/opus create meu-app
|
|
30
28
|
cd meu-app && git init && pnpm install && pnpm test
|
|
31
29
|
```
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Release recém-saída (menos de 24h): a quarentena do pnpm resolve o `dlx` pra versão
|
|
39
|
-
ANTIGA em silêncio ("Comando desconhecido" = sintoma clássico). Fure com a versão
|
|
40
|
-
explícita — `pnpm dlx @softize/opus@<versão> create meu-app` — ou com a flag
|
|
41
|
-
`pnpm --config.minimum-release-age=0 dlx …`. Dentro de projeto o pnpm se resolve
|
|
42
|
-
sozinho (auto-exclui o Opus da quarentena no install).
|
|
31
|
+
O comando cria a estrutura inicial e instala a versão estável disponível. Para experimentar
|
|
32
|
+
uma versão específica, acrescente-a ao pacote: `pnpm dlx @softize/opus@<versão> create meu-app`.
|
|
33
|
+
Se o pnpm informar que o diretório global de binários não está no `PATH`, execute `pnpm setup`
|
|
34
|
+
e abra uma nova sessão do terminal antes de tentar novamente.
|
|
43
35
|
|
|
44
36
|
Nasce com: `opus.config.ts` + domínio-exemplo canônico (0 violações, spec documentada),
|
|
45
37
|
vite + react + tema do Opus (Tailwind v4 CSS-first), dev server na porta que o Maestro
|
|
@@ -59,8 +51,8 @@ pnpm dlx @softize/opus create apps/portal # o app (modo detectado)
|
|
|
59
51
|
|
|
60
52
|
## Carregar o Opus num projeto existente
|
|
61
53
|
|
|
62
|
-
> O
|
|
63
|
-
>
|
|
54
|
+
> O `opus.json` registra a versão usada pelo projeto. Se o arquivo ainda não existe, o setup
|
|
55
|
+
> cria a estrutura necessária antes das demais etapas.
|
|
64
56
|
|
|
65
57
|
A versão do Opus fica pinada em `opus.json`. O `opus setup` é per-app: grava o `opus.json`,
|
|
66
58
|
mantém o bloco gerenciado do `CLAUDE.md` (fora dele o arquivo é seu) e semeia o dia zero
|
|
@@ -6,7 +6,7 @@ title: Atualizar o Opus
|
|
|
6
6
|
|
|
7
7
|
Projeto em produção fica meses sem tocar no Opus — e um dia precisa pular várias
|
|
8
8
|
versões de uma vez. O ritual é o mesmo para humano e IA, e não depende de memória:
|
|
9
|
-
cada
|
|
9
|
+
cada etapa está documentada ou é verificada por um gate que informa o que precisa ser corrigido.
|
|
10
10
|
|
|
11
11
|
## 1. Saber que está atrás
|
|
12
12
|
|
package/src/ui/docs/registry.tsx
CHANGED
|
@@ -39,7 +39,7 @@ import runtimeMd from './content/runtime.md?raw'
|
|
|
39
39
|
import uiMd from './content/ui.md?raw'
|
|
40
40
|
import cliMd from './content/cli.md?raw'
|
|
41
41
|
import tokensMd from './content/tokens.md?raw'
|
|
42
|
-
import
|
|
42
|
+
import communicationMd from './content/communication.md?raw'
|
|
43
43
|
import customizationMd from './content/customization.md?raw'
|
|
44
44
|
|
|
45
45
|
// — Componentes —
|
|
@@ -267,7 +267,7 @@ export const UI_SECTIONS: DocSection[] = [
|
|
|
267
267
|
{
|
|
268
268
|
pages: [
|
|
269
269
|
{ slug: 'tokens', title: 'Tokens & Tema', render: doc(tokensMd) },
|
|
270
|
-
{ slug: '
|
|
270
|
+
{ slug: 'communication', title: 'Comunicação', render: doc(communicationMd) },
|
|
271
271
|
{ slug: 'customization', title: 'Customização', render: doc(customizationMd) },
|
|
272
272
|
],
|
|
273
273
|
},
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Microcopy
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Microcopy
|
|
6
|
-
|
|
7
|
-
Código em inglês; o que humano lê (UI, comentário, doc) em pt-BR. Frases começam com
|
|
8
|
-
maiúscula e terminam com ponto; labels curtos em sentence case, sem ponto. **Esta página
|
|
9
|
-
é a fonte** — `build-opus-ui` aplica esta convenção (regra duplicada em vez de apontada é
|
|
10
|
-
defeito).
|
|
11
|
-
|
|
12
|
-
## Língua por camada
|
|
13
|
-
|
|
14
|
-
> Regra dura — não tem caso a caso.
|
|
15
|
-
|
|
16
|
-
| Camada | Língua |
|
|
17
|
-
|---|---|
|
|
18
|
-
| Identificadores de código (vars, funções, tipos, arquivos, dirs, domínios) | Inglês |
|
|
19
|
-
| Nomes de action / rota | Inglês (`resource.verb`) |
|
|
20
|
-
| Colunas e tabelas de banco | Inglês (snake_case) |
|
|
21
|
-
| Valores de código (enums, status, chaves de dict) | Inglês — mesmo em exemplos e fixtures (`active`, não `ativo`); a UI mostra o label pt |
|
|
22
|
-
| Texto de UI visível (labels, headings, botões, placeholders, mensagens) | pt-BR |
|
|
23
|
-
| Comentários e docs (`.md`) | pt-BR |
|
|
24
|
-
|
|
25
|
-
## Frase vs label
|
|
26
|
-
|
|
27
|
-
> Frase (mensagem, descrição, tooltip, help): maiúscula no início, ponto no fim. Label
|
|
28
|
-
> (botão, heading, item de menu, chip): sentence case, sem ponto.
|
|
29
|
-
|
|
30
|
-
| Tipo | Assim | Assim não |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| Frase | Opus não inicializado. | ~~opus nao inicializado~~ |
|
|
33
|
-
| Frase | O Multica não respondeu — tente de novo. | ~~ERRO: request failed (500)~~ |
|
|
34
|
-
| Label | Publicar | ~~PUBLICAR~~ |
|
|
35
|
-
| Label | Nova sessão | ~~Nova sessão.~~ |
|
|
36
|
-
| Placeholder | Selecione um cliente… | ~~Selecionar~~ · ~~digite o nome…~~ |
|
|
37
|
-
|
|
38
|
-
## As regras que mais pegam
|
|
39
|
-
|
|
40
|
-
> Erros recorrentes de revisão — atenção redobrada nestes.
|
|
41
|
-
|
|
42
|
-
- **Maiúscula é ortografia, não estilo.** Toda frase começa com maiúscula — em UI,
|
|
43
|
-
hint/help **e comentário de código** — e nome próprio idem (Engineer, Multica, GitHub).
|
|
44
|
-
Vale com interpolação: mensagem que começaria com valor ganha um artigo na frente
|
|
45
|
-
(`O workspace '${slug}' não existe…`).
|
|
46
|
-
- **Frase fluida, não telegrama.** Símbolo não é conector: nada de `—`/`+`/`≈` amarrando
|
|
47
|
-
ideias em label ou help. `Staff — acesso ao back-office + todos os workspaces` vira
|
|
48
|
-
label `Staff` + help `Tem acesso ao back-office e a todos os workspaces.`.
|
|
49
|
-
- **"Opus" e "Softize" são nomes próprios.** Em prosa, maiúscula (`o Opus`, `a Softize`);
|
|
50
|
-
os tokens técnicos ficam minúsculos: `opus check`, `@softize/opus`, `opus.json`,
|
|
51
|
-
`softize.com.br`. É o nome → maiúscula; é código → minúscula.
|
|
52
|
-
- **Abreviação é último caso.** Por extenso: `mínimo`, `máximo`, `configuração`.
|
|
53
|
-
`Config indisponível.` é duplamente errado (seco E abreviado): `A configuração não
|
|
54
|
-
carregou.`. `Ex.:` em placeholder é tolerado (com `E` maiúsculo).
|
|
55
|
-
- **Placeholder de seleção segue UM padrão** (select simples, buscável, múltiplo):
|
|
56
|
-
`Selecione <artigo> <coisa>…` — com `…` (o caractere único), nunca o genérico
|
|
57
|
-
`Selecionar`. Declare no contrato (`fields.<campo>.placeholder`) — o default do
|
|
58
|
-
componente é rede de segurança, não estilo; dois pickers na mesma tela com padrões
|
|
59
|
-
diferentes é defeito.
|
|
60
|
-
- **Nada de maiúsculo deliberado.** Sem ALL-CAPS — nem a classe `uppercase` — em labels,
|
|
61
|
-
headers ou badges.
|
|
62
|
-
- **Exemplos são neutros e duráveis.** Nada de cliente real ou com cara de real: use
|
|
63
|
-
Empresa X / Empresa Y (`contato@empresa-x.com.br`). Exemplo "de verdade" envelhece,
|
|
64
|
-
vaza contexto e vira dívida.
|
|
65
|
-
|
|
66
|
-
## Tom
|
|
67
|
-
|
|
68
|
-
> Fale com o usuário, não com o log.
|
|
69
|
-
|
|
70
|
-
- **Calmo e informativo, não alarmista.** "Indisponível" em vez de "ERRO"/"FALHOU".
|
|
71
|
-
Não culpe o usuário.
|
|
72
|
-
- **Orientado à ação.** Quando dá, diga o próximo passo: `Inicie o ambiente`,
|
|
73
|
-
`Crie a primeira acima`.
|
|
74
|
-
- **Conciso, mas natural — não telegráfico.** Prefira a forma completa do verbo a um
|
|
75
|
-
corte abrupto. O meio-termo é a régua: nem seco demais (`rode no projeto`) nem manual
|
|
76
|
-
técnico (jargão de arquitetura num help).
|
|
77
|
-
- **Explique pelo efeito, não pelo mecanismo.** Se precisou citar sistema interno pra
|
|
78
|
-
explicar (`o push sobrescreve o runtime`), reescreva pelo que acontece pro usuário
|
|
79
|
-
(`os agentes deste workspace passam a usar esta skill`). Mecanismo é doc/comentário,
|
|
80
|
-
não tooltip.
|
|
81
|
-
- **Nada de endpoint, status ou stack na tela** — detalhe técnico vai pro console/log.
|
|
82
|
-
- **Termos do produto** (sessão, ambiente, cliente, agente), não do código. E o mesmo
|
|
83
|
-
termo sempre: se a UI fala "cliente", nenhum label diz "client".
|