@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/README.md +31 -1
  3. package/bin/cli.mjs +97 -27
  4. package/bin/lib/check.mjs +55 -43
  5. package/bin/lib/copy.mjs +2202 -0
  6. package/bin/lib/create.mjs +227 -39
  7. package/bin/lib/db-migrate-runner.mjs +9 -6
  8. package/bin/lib/db-project-path.mjs +20 -0
  9. package/bin/lib/db-scaffold-runner.mjs +23 -8
  10. package/bin/lib/db.mjs +6 -4
  11. package/bin/lib/gen.mjs +60 -29
  12. package/bin/lib/init.mjs +212 -56
  13. package/bin/lib/introspect.mjs +3 -2
  14. package/bin/lib/materialize.mjs +623 -97
  15. package/bin/lib/postinstall.mjs +6 -5
  16. package/bin/lib/validate-skill.mjs +502 -30
  17. package/docs/code-style.md +142 -7
  18. package/docs/consumer-upgrade-propagation.md +4 -3
  19. package/docs/releasing.md +28 -17
  20. package/package.json +6 -1
  21. package/registry/git/pre-push.d/00-opus-copy +14 -0
  22. package/registry/git/pre-push.d/opus +7 -21
  23. package/registry/git/run-opus-pre-push.mjs +141 -0
  24. package/registry/hooks/opus-check-on-stop.mjs +13 -31
  25. package/registry/instructions/opus.md +11 -5
  26. package/registry/skills/build-opus-ui/SKILL.md +5 -4
  27. package/registry/skills/create-opus-action/SKILL.md +4 -4
  28. package/registry/skills/implement-opus-change/SKILL.md +7 -5
  29. package/registry/skills/upgrade-opus/SKILL.md +8 -4
  30. package/registry/skills/upgrade-opus/references/upgrade-checklist.md +4 -1
  31. package/registry/templates/app/package.json +4 -0
  32. package/registry/templates/app/pnpm-workspace.yaml +3 -2
  33. package/registry/templates/app/src/domains/tasks/actions/list.ts +1 -1
  34. package/registry/templates/monorepo/pnpm-workspace.yaml +3 -1
  35. package/src/ui/components/patterns/split.tsx +66 -24
  36. package/src/ui/docs/content/cli.md +8 -7
  37. package/src/ui/docs/content/communication.md +79 -126
  38. package/src/ui/docs/content/getting-started.md +29 -16
  39. package/src/ui/docs/content/split.md +43 -3
  40. package/src/ui/react.tsx +1 -1
  41. package/registry/skills/write-product-communication/SKILL.md +0 -28
  42. package/registry/skills/write-product-communication/agents/openai.yaml +0 -4
  43. package/registry/templates/app/_npmrc +0 -1
  44. 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. 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.
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), `CLAUDE.md` (bloco gerenciado), `.claude/memory/`
39
- e o CI de fábrica.
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 (nada de `.npmrc`/workspace
43
- yaml aninhado), **avisando** o que a raiz precisa ter (glob de packages, escopo do
44
- registry, allowBuilds) sem tocar nos seus arquivos:
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 `opus.json`,
58
- mantém o bloco gerenciado do `CLAUDE.md` (fora dele o arquivo é seu) e semeia o dia zero
59
- (`.claude/memory/`, CI) se faltarem. Os componentes e hooks vêm do barrel
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 per-app (idempotente): pin + bloco do CLAUDE.md + dia zero.
64
- npx @softize/opus setup
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` é o primitive espacial da UI. A ordem dos `Pane` define esquerda→direita (ou cima→baixo); o pane não sabe onde está. Sem `resizable`, é flex simples. Com ele, a fronteira vira arrastável sem trocar o modelo do componente.
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
- Um rail não é uma prop especial: é o último pane.
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={28} minSize={20} inset="none"><Inspector /></Pane>
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,4 +0,0 @@
1
- interface:
2
- display_name: "Comunicação de produto"
3
- short_description: "Escreva textos claros, humanos e úteis"
4
- default_prompt: "Use $write-product-communication para revisar esta comunicação pelo ponto de vista do leitor."
@@ -1 +0,0 @@
1
- @softize:registry=https://registry.softize.com.br/
@@ -1 +0,0 @@
1
- @softize:registry=https://registry.softize.com.br/