@softize/opus 11.1.1 → 12.0.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 +63 -1
- package/README.md +31 -1
- package/bin/cli.mjs +97 -27
- package/bin/lib/check.mjs +55 -43
- package/bin/lib/copy.mjs +2202 -0
- package/bin/lib/create.mjs +227 -39
- package/bin/lib/db-migrate-runner.mjs +9 -6
- package/bin/lib/db-project-path.mjs +20 -0
- package/bin/lib/db-scaffold-runner.mjs +23 -8
- package/bin/lib/db.mjs +6 -4
- package/bin/lib/gen.mjs +60 -29
- package/bin/lib/init.mjs +212 -56
- package/bin/lib/introspect.mjs +3 -2
- package/bin/lib/materialize.mjs +623 -97
- package/bin/lib/postinstall.mjs +6 -5
- package/bin/lib/validate-skill.mjs +502 -30
- package/docs/code-style.md +142 -7
- package/docs/consumer-upgrade-propagation.md +4 -3
- package/docs/releasing.md +28 -17
- package/package.json +6 -1
- package/registry/git/pre-push.d/00-opus-copy +14 -0
- package/registry/git/pre-push.d/opus +7 -21
- package/registry/git/run-opus-pre-push.mjs +141 -0
- package/registry/hooks/opus-check-on-stop.mjs +13 -31
- package/registry/instructions/opus.md +11 -5
- package/registry/skills/build-opus-ui/SKILL.md +5 -4
- package/registry/skills/create-opus-action/SKILL.md +4 -4
- package/registry/skills/implement-opus-change/SKILL.md +7 -5
- package/registry/skills/upgrade-opus/SKILL.md +8 -4
- package/registry/skills/upgrade-opus/references/upgrade-checklist.md +4 -1
- package/registry/templates/app/package.json +4 -0
- package/registry/templates/app/pnpm-workspace.yaml +3 -2
- package/registry/templates/app/src/domains/tasks/actions/list.ts +1 -1
- package/registry/templates/monorepo/pnpm-workspace.yaml +3 -1
- package/src/ui/components/patterns/split.tsx +66 -24
- package/src/ui/docs/content/cli.md +8 -7
- package/src/ui/docs/content/communication.md +79 -126
- package/src/ui/docs/content/getting-started.md +29 -16
- package/src/ui/docs/content/split.md +43 -3
- package/src/ui/react.tsx +1 -1
- package/registry/skills/write-product-communication/SKILL.md +0 -28
- package/registry/skills/write-product-communication/agents/openai.yaml +0 -4
- package/registry/templates/app/_npmrc +0 -1
- package/registry/templates/monorepo/_npmrc +0 -1
|
@@ -23,25 +23,35 @@ base versionada.
|
|
|
23
23
|
> Projeto novo não se monta à mão: o esqueleto canônico sai do `opus create`, com os
|
|
24
24
|
> pré-requisitos do protocolo, da UI e do preview já plugados — e os gates verdes.
|
|
25
25
|
|
|
26
|
+
O Opus e a Base ficam no npm público: leitura não exige token nem configuração de escopo.
|
|
27
|
+
Crie o projeto e materialize as duas camadas antes dos gates:
|
|
28
|
+
|
|
26
29
|
```bash
|
|
27
30
|
pnpm dlx @softize/opus create meu-app
|
|
28
|
-
cd meu-app && git init && pnpm install && pnpm test
|
|
31
|
+
cd meu-app && git init && pnpm install && pnpm run setup && pnpm test
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
O comando cria a estrutura inicial e instala a versão estável disponível.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
O comando cria a estrutura inicial e instala a versão estável disponível. Em uma máquina nova,
|
|
35
|
+
se o `dlx` informar que o diretório global de binários não está no `PATH`, execute `pnpm setup`
|
|
36
|
+
e abra outra sessão do terminal. Se o setup encontrar uma seção antiga do pnpm no arquivo de
|
|
37
|
+
inicialização do shell (`ERR_PNPM_BAD_SHELL_SECTION`), `pnpm setup --force` substitui somente
|
|
38
|
+
esse bloco.
|
|
39
|
+
|
|
40
|
+
Durante as primeiras 24 horas de uma release, a quarentena do pnpm pode resolver silenciosamente
|
|
41
|
+
uma versão anterior. Se o CLI responder com “Comando desconhecido”, informe a versão explicitamente
|
|
42
|
+
com `pnpm dlx @softize/opus@<versão> create meu-app` ou desative a quarentena apenas nessa chamada
|
|
43
|
+
com `pnpm --config.minimum-release-age=0 dlx …`. Dentro do projeto, o workspace exclui Opus e Base
|
|
44
|
+
da quarentena para preservar o par validado.
|
|
35
45
|
|
|
36
46
|
Nasce com: `opus.config.ts` + domínio-exemplo canônico (0 violações, spec documentada),
|
|
37
47
|
vite + react + tema do Opus (Tailwind v4 CSS-first), dev server na porta que o Maestro
|
|
38
|
-
injeta no preview, `opus.json` (pin),
|
|
39
|
-
e o
|
|
48
|
+
injeta no preview, `opus.json` (pin), instruções, skills e hooks gerenciados. A Base é
|
|
49
|
+
dona do método geral, memória e revisão; o Opus acrescenta somente o conhecimento do SDK.
|
|
40
50
|
|
|
41
51
|
**Monorepo:** a raiz nasce do `--monorepo` e cada app nasce dentro dela — o create
|
|
42
|
-
detecta o `pnpm-workspace.yaml` e gera só o que é do app (
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
detecta o `pnpm-workspace.yaml` e gera só o que é do app (sem workspace yaml aninhado),
|
|
53
|
+
**avisando** o que a raiz precisa ter (glob de packages, allowBuilds e exclusões de
|
|
54
|
+
quarentena para Opus/Base) sem tocar nos seus arquivos:
|
|
45
55
|
|
|
46
56
|
```bash
|
|
47
57
|
pnpm dlx @softize/opus create meu-cliente --monorepo # a raiz do workspace
|
|
@@ -54,14 +64,17 @@ pnpm dlx @softize/opus create apps/portal # o app (modo detectado)
|
|
|
54
64
|
> O `opus.json` registra a versão usada pelo projeto. Se o arquivo ainda não existe, o setup
|
|
55
65
|
> cria a estrutura necessária antes das demais etapas.
|
|
56
66
|
|
|
57
|
-
A versão do Opus fica pinada em `opus.json`. O `opus setup` é per-app: grava o
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
`@softize/opus/ui/react`; o tema, por CSS.
|
|
67
|
+
A versão do Opus fica pinada em `opus.json`. O `opus setup` é per-app: grava o marcador,
|
|
68
|
+
o inventário de copy e as projeções específicas do SDK. O `base setup` materializa o
|
|
69
|
+
método geral, memória, agentes e revisão na raiz do repositório. Os componentes vêm do
|
|
70
|
+
barrel `@softize/opus/ui/react`; o tema, por CSS.
|
|
61
71
|
|
|
62
72
|
```bash
|
|
63
|
-
# Bootstrap
|
|
64
|
-
|
|
73
|
+
# Bootstrap idempotente de um projeto existente.
|
|
74
|
+
pnpm add @softize/opus
|
|
75
|
+
pnpm add -D @softize/base
|
|
76
|
+
pnpm exec opus setup
|
|
77
|
+
pnpm exec base setup
|
|
65
78
|
|
|
66
79
|
# index.css do app — o tema canônico + os componentes do Opus no scan do Tailwind.
|
|
67
80
|
@import '@softize/opus/ui/theme.css';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## Split & Pane
|
|
2
2
|
|
|
3
|
-
`Split`
|
|
3
|
+
`Split` organiza áreas lado a lado ou uma sobre a outra. A ordem dos `Pane` define a posição de cada área. Sem `resizable`, o layout usa flex; com essa opção, a pessoa também pode ajustar as divisórias com ponteiro ou teclado.
|
|
4
4
|
|
|
5
5
|
```tsx preview
|
|
6
6
|
render(
|
|
@@ -23,11 +23,51 @@ O `Pane` traz `inset="md"` por default. Use `none` para chrome, navegação e co
|
|
|
23
23
|
|
|
24
24
|
## Rail
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Quando uma área precisa continuar legível em telas largas, use uma unidade absoluta para o tamanho inicial ou mínimo. Números continuam representando porcentagens; strings aceitam `%`, `rem`, `em`, `vh`, `vw` e `px`. Prefira `rem` para acompanhar a escala tipográfica configurada pela aplicação.
|
|
27
27
|
|
|
28
28
|
```tsx
|
|
29
29
|
<Split resizable>
|
|
30
30
|
<Pane grow inset="none"><Main /></Pane>
|
|
31
|
-
<Pane initialSize=
|
|
31
|
+
<Pane initialSize="28rem" minSize="20rem" inset="none"><Inspector /></Pane>
|
|
32
32
|
</Split>
|
|
33
33
|
```
|
|
34
|
+
|
|
35
|
+
## Persistência
|
|
36
|
+
|
|
37
|
+
Um layout pode ser restaurado sem acoplar `Split` a um mecanismo específico de armazenamento. Dê um `id` estável a cada `Pane`, leia o valor salvo para formar `defaultLayout` e persista apenas mudanças concluídas pela pessoa.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
function readLayout(key: string): SplitLayout | undefined {
|
|
41
|
+
if (typeof window === 'undefined') return undefined
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const parsed: unknown = JSON.parse(localStorage.getItem(key) ?? 'null')
|
|
45
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined
|
|
46
|
+
const entries = Object.entries(parsed)
|
|
47
|
+
const valid = entries.every(([id, size]) =>
|
|
48
|
+
id !== '' && typeof size === 'number' && Number.isFinite(size) && size >= 0 && size <= 100,
|
|
49
|
+
)
|
|
50
|
+
return valid ? Object.fromEntries(entries) : undefined
|
|
51
|
+
} catch {
|
|
52
|
+
return undefined
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const defaultLayout = readLayout('workspace-layout')
|
|
57
|
+
|
|
58
|
+
<Split
|
|
59
|
+
id="workspace"
|
|
60
|
+
resizable
|
|
61
|
+
defaultLayout={defaultLayout}
|
|
62
|
+
onLayoutChanged={(layout, meta) => {
|
|
63
|
+
if (meta.isUserInteraction) {
|
|
64
|
+
localStorage.setItem('workspace-layout', JSON.stringify(layout))
|
|
65
|
+
}
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<Pane id="navigation" initialSize="28rem" minSize="28rem"><Navigation /></Pane>
|
|
69
|
+
<Pane id="content" grow><Content /></Pane>
|
|
70
|
+
</Split>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Em aplicações renderizadas no servidor, leia o armazenamento somente no cliente. `onLayoutChanged` também permite usar `sessionStorage` ou uma camada própria quando o layout precisa acompanhar outro escopo.
|
package/src/ui/react.tsx
CHANGED
|
@@ -207,7 +207,7 @@ export type { PageProps } from './components/patterns/page.tsx'
|
|
|
207
207
|
|
|
208
208
|
// Layout composicional: Split decide a relação espacial; Pane carrega conteúdo com inset.
|
|
209
209
|
export { Split, Pane } from './components/patterns/split.tsx'
|
|
210
|
-
export type { SplitProps, PaneProps } from './components/patterns/split.tsx'
|
|
210
|
+
export type { SplitProps, PaneProps, PaneSize, SplitLayout, SplitLayoutChange } from './components/patterns/split.tsx'
|
|
211
211
|
|
|
212
212
|
// Barra lateral composicional: header/conteúdo/footer e navegação, sem possuir o layout.
|
|
213
213
|
export { PaneHeader, PaneContent, PaneFooter, Sidebar, SidebarItem, SidebarNav } from './components/patterns/sidebar.tsx'
|
|
@@ -1,28 +0,0 @@
|
|
|
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 -->
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@softize:registry=https://registry.softize.com.br/
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@softize:registry=https://registry.softize.com.br/
|