@softize/opus 28.0.0 → 30.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/bin/cli.mjs +68 -3
- package/bin/lib/check.mjs +86 -10
- package/bin/lib/copy.mjs +505 -67
- package/bin/lib/materialize.mjs +99 -1
- package/docs/adr/0028-schedules-run-actions-as-the-system-by-action-opt-in.md +1 -1
- package/docs/adr/0037-design-data-lives-outside-the-contract.md +1 -1
- package/docs/adr/0045-surface-replaces-content-and-card.md +3 -0
- package/docs/adr/0061-claude-md-imports-agents-md.md +41 -0
- package/docs/adr/0062-listas-contidas-e-texto-flexivel.md +68 -0
- package/docs/adr/0063-metadados-das-superficies.md +44 -0
- package/docs/adr/README.md +6 -0
- package/docs/code-style.md +47 -8
- package/docs/protocol.md +1 -1
- package/docs/releasing.md +7 -0
- package/package.json +1 -1
- package/registry/instructions/opus.md +3 -1
- package/registry/skills/build-opus-ui/SKILL.md +6 -4
- package/registry/skills/build-opus-ui/references/evaluations.md +10 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +10 -2
- package/registry/skills/maintain-opus-docs/SKILL.md +2 -1
- package/registry/skills/maintain-opus-docs/references/editorial-standard.md +9 -0
- package/registry/skills/maintain-opus-docs/references/evaluations.md +8 -0
- package/registry/templates/app/pnpm-workspace.yaml +1 -1
- package/src/core/system-actor.ts +1 -1
- package/src/core/types.ts +1 -1
- package/src/ui/components/patterns/list.tsx +19 -10
- package/src/ui/components/patterns/page.tsx +27 -0
- package/src/ui/components/patterns/structural-header.tsx +25 -3
- package/src/ui/components/patterns/surface.tsx +36 -8
- package/src/ui/components/primitives/dialog.tsx +74 -42
- package/src/ui/components/primitives/drawer.tsx +69 -42
- package/src/ui/components/primitives/table.tsx +3 -3
- package/src/ui/docs/content/action-list.md +15 -8
- package/src/ui/docs/content/actions.md +1 -1
- package/src/ui/docs/content/auth.md +3 -3
- package/src/ui/docs/content/cli.md +6 -0
- package/src/ui/docs/content/communication.md +10 -8
- package/src/ui/docs/content/dialog.md +39 -0
- package/src/ui/docs/content/drawer.md +36 -0
- package/src/ui/docs/content/events.md +13 -13
- package/src/ui/docs/content/installation.md +4 -0
- package/src/ui/docs/content/log.md +1 -1
- package/src/ui/docs/content/page.md +30 -1
- package/src/ui/docs/content/queue.md +2 -2
- package/src/ui/docs/content/router.md +1 -1
- package/src/ui/docs/content/scheduler.md +15 -15
- package/src/ui/docs/content/surface.md +41 -8
- package/src/ui/docs/content/table.md +7 -0
- package/src/ui/docs/content/testing.md +4 -4
- package/src/ui/react.tsx +4 -0
- package/src/vite/design.ts +1 -1
package/bin/lib/materialize.mjs
CHANGED
|
@@ -27,6 +27,7 @@ const REGISTRY = join(PACKAGE_ROOT, 'registry')
|
|
|
27
27
|
const BLOCK_SOURCE = 'registry/instructions/opus.md'
|
|
28
28
|
const BLOCK_END = '<!-- softize-managed:end @softize/opus -->'
|
|
29
29
|
const MANAGED_ROOTS = ['.agents/skills', '.claude/skills', '.claude/hooks', '.github/workflows', '.githooks/pre-push.d']
|
|
30
|
+
const CLAUDE_IMPORT = '@AGENTS.md'
|
|
30
31
|
|
|
31
32
|
const normalizedLineEndings = (content) => content.replace(/\r\n?/gu, '\n')
|
|
32
33
|
const hash = (content) => createHash('sha256').update(normalizedLineEndings(content)).digest('hex')
|
|
@@ -533,6 +534,103 @@ function reconcileInstructions(root, file, mode, errors, changes) {
|
|
|
533
534
|
}
|
|
534
535
|
}
|
|
535
536
|
|
|
537
|
+
// Blocos gerenciados de qualquer pacote. Um marcador de início ilegível não identifica dono e
|
|
538
|
+
// conta como texto do projeto. Mesmo critério da Base (@softize/base, ADR 0006).
|
|
539
|
+
function managedBlocks(content) {
|
|
540
|
+
const blocks = []
|
|
541
|
+
let cursor = 0
|
|
542
|
+
for (const match of content.matchAll(/<!-- softize-managed:start (\{[^\n]+\}) -->/g)) {
|
|
543
|
+
let meta
|
|
544
|
+
try {
|
|
545
|
+
meta = JSON.parse(match[1])
|
|
546
|
+
} catch {
|
|
547
|
+
continue
|
|
548
|
+
}
|
|
549
|
+
if (typeof meta?.package !== 'string') continue
|
|
550
|
+
const openEnd = match.index + match[0].length
|
|
551
|
+
const endMarker = `<!-- softize-managed:end ${meta.package} -->`
|
|
552
|
+
const endAt = content.indexOf(endMarker, openEnd)
|
|
553
|
+
if (match.index < cursor || endAt === -1 || content.slice(openEnd, endAt).includes('softize-managed:start')) return null
|
|
554
|
+
const end = endAt + endMarker.length
|
|
555
|
+
blocks.push({ start: match.index, end, package: meta.package, text: content.slice(match.index, end) })
|
|
556
|
+
cursor = end
|
|
557
|
+
}
|
|
558
|
+
return blocks
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Texto do projeto fora dos blocos gerenciados e da linha de import, normalizado para comparar o
|
|
562
|
+
// CLAUDE.md legado com o AGENTS.md sem depender de fim de linha ou de linhas em branco.
|
|
563
|
+
function freeInstructions(content, blocks) {
|
|
564
|
+
let rest = ''
|
|
565
|
+
let cursor = 0
|
|
566
|
+
for (const block of blocks) {
|
|
567
|
+
rest += content.slice(cursor, block.start)
|
|
568
|
+
cursor = block.end
|
|
569
|
+
}
|
|
570
|
+
rest += content.slice(cursor)
|
|
571
|
+
return normalizedLineEndings(rest)
|
|
572
|
+
.split('\n')
|
|
573
|
+
.map((line) => line.trimEnd())
|
|
574
|
+
.filter((line) => line !== CLAUDE_IMPORT)
|
|
575
|
+
.join('\n')
|
|
576
|
+
.replace(/\n{3,}/gu, '\n\n')
|
|
577
|
+
.trim()
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// O CLAUDE.md só importa o AGENTS.md, que concentra as instruções para qualquer agente. O Opus
|
|
581
|
+
// remove dele apenas o próprio bloco; blocos de outros pacotes continuam depois do import até que
|
|
582
|
+
// o pacote dono os remova, para que versões antigas e novas convivam sem reescrever o arquivo uma
|
|
583
|
+
// da outra. Texto do projeto que só existe no CLAUDE.md é preservado e reprovado.
|
|
584
|
+
function reconcileClaudeImport(root, mode, errors, changes) {
|
|
585
|
+
const destination = 'CLAUDE.md'
|
|
586
|
+
const pending =
|
|
587
|
+
`${destination}: deve conter a linha ${CLAUDE_IMPORT}, que importa o AGENTS.md, seguida apenas dos ` +
|
|
588
|
+
'blocos de outros pacotes, quando houver; rode opus setup.'
|
|
589
|
+
const currentFile = readMaterializedFile(root, destination, errors)
|
|
590
|
+
if (currentFile === null) return
|
|
591
|
+
const current = currentFile.exists ? currentFile.content : ''
|
|
592
|
+
const own = findBlock(current)
|
|
593
|
+
const blocks = managedBlocks(current)
|
|
594
|
+
if (own?.malformed || blocks === null) {
|
|
595
|
+
errors.push(`${destination}: bloco gerenciado malformado.`)
|
|
596
|
+
return
|
|
597
|
+
}
|
|
598
|
+
if (own !== null && (own.owner?.package !== PACKAGE_NAME || hash(own.body) !== own.owner.sha256)) {
|
|
599
|
+
errors.push(`${destination}: bloco Opus foi editado ou perdeu sua identificação de origem; preservado.`)
|
|
600
|
+
return
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const free = freeInstructions(current, blocks)
|
|
604
|
+
if (free !== '') {
|
|
605
|
+
const agentsFile = readMaterializedFile(root, 'AGENTS.md', errors)
|
|
606
|
+
if (agentsFile === null) return
|
|
607
|
+
const agents = agentsFile.exists ? agentsFile.content : ''
|
|
608
|
+
if (free !== freeInstructions(agents, managedBlocks(agents) ?? [])) {
|
|
609
|
+
errors.push(
|
|
610
|
+
`${destination}: tem instruções que não estão no AGENTS.md; preservado. O CLAUDE.md passa a conter só ` +
|
|
611
|
+
`${CLAUDE_IMPORT}, então mova essas instruções para o AGENTS.md e rode opus setup.`,
|
|
612
|
+
)
|
|
613
|
+
return
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const foreign = blocks.filter((block) => block.package !== PACKAGE_NAME).map((block) => normalizedLineEndings(block.text))
|
|
618
|
+
const expected = `${[CLAUDE_IMPORT, ...foreign].join('\n\n')}\n`
|
|
619
|
+
if (currentFile.exists && managedTextEquivalent(current, expected)) return
|
|
620
|
+
if (mode === 'check') errors.push(pending)
|
|
621
|
+
else if (
|
|
622
|
+
replaceMaterializedFile(
|
|
623
|
+
root,
|
|
624
|
+
destination,
|
|
625
|
+
currentFile.exists ? withProjectLineEndings(expected, current) : expected,
|
|
626
|
+
currentFile,
|
|
627
|
+
errors,
|
|
628
|
+
)
|
|
629
|
+
) {
|
|
630
|
+
changes.push(`${currentFile.exists ? 'atualizado' : 'criado'} ${destination} como import do AGENTS.md`)
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
536
634
|
function isOpusHook(hook) { return typeof hook?.command === 'string' && hook.command.includes('.claude/hooks/opus-check-on-stop.mjs') }
|
|
537
635
|
|
|
538
636
|
function isPlainObject(value) {
|
|
@@ -792,7 +890,7 @@ export function materializeOpus(root, mode = 'setup', options = {}) {
|
|
|
792
890
|
removeObsolete(target, expected, mode, errors, changes)
|
|
793
891
|
detectLegacyArtifacts(target, errors)
|
|
794
892
|
reconcileInstructions(target, 'AGENTS.md', mode, errors, changes)
|
|
795
|
-
|
|
893
|
+
reconcileClaudeImport(target, mode, errors, changes)
|
|
796
894
|
reconcileSettings(target, mode, errors, changes)
|
|
797
895
|
configureGit(target, mode, errors, changes)
|
|
798
896
|
return { ok: errors.length === 0, errors, changes, expected: [...expected.keys()] }
|
|
@@ -45,7 +45,7 @@ HTTP sem usuário; o acesso do sistema é opt-in por action e negado por padrão
|
|
|
45
45
|
`{ kind: 'schedule', scheduleName }` — ou `background` com essa provenance original. O helper
|
|
46
46
|
`isSystemActor(ctx)`, exportado pelo core, responde se o ator é o sistema, para que um
|
|
47
47
|
`authorize` possa aceitá-lo de forma explícita: `(ctx) => isSystemActor(ctx) ||
|
|
48
|
-
ctx.can('
|
|
48
|
+
ctx.can('ledger:close')`. O helper não lê a provenance, que qualquer código servidor pode
|
|
49
49
|
preencher: ele consulta um registro interno dos contextos que o próprio runtime criou para o
|
|
50
50
|
sistema. `requires` continua declarativo: o sistema não detém permissões, e o manifest mostra
|
|
51
51
|
`automatable` ao lado de `permission`.
|
|
@@ -54,7 +54,7 @@ Forças em tensão:
|
|
|
54
54
|
- uma action ligada a um handler real (`bindAction`) mantém esse handler, como hoje.
|
|
55
55
|
3. **Cenários são registrados fora do contrato, pelo nome da action.** O plugin ganha a opção
|
|
56
56
|
`scenarios`, com um ou mais globs. Os módulos casados exportam cenários criados por
|
|
57
|
-
`defineDesignScenario(
|
|
57
|
+
`defineDesignScenario(contract, response)`, e a resposta pode ser um valor ou uma função tipada
|
|
58
58
|
pela entrada e pela saída do contrato. O cenário vence a resposta padrão. Um cenário para uma
|
|
59
59
|
action inexistente é erro visível no preview, não um silêncio.
|
|
60
60
|
4. **O Opus não decide onde os cenários ficam.** A opção não tem default dentro do código da
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
`Surface`.
|
|
18
18
|
- **Não altera:** `Page`, `Dialog`, `Drawer` e `Pane`, que mantêm famílias, slots e mídia próprios.
|
|
19
19
|
|
|
20
|
+
A ADR 0063 substitui parcialmente esta decisão: `SurfaceMeta` passa a representar a faixa
|
|
21
|
+
de metadados; o contador na linha do título passa a usar `SurfaceCount`.
|
|
22
|
+
|
|
20
23
|
## Contexto
|
|
21
24
|
|
|
22
25
|
Quem monta uma tela precisa delimitar e nomear um trecho dela: uma seção da página, um grupo de
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# ADR 0061 — O `CLAUDE.md` importa o `AGENTS.md`
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-10-15.
|
|
5
|
+
- **Acompanha:** ADR 0006 do `@softize/base`, que define o mesmo formato.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
O `opus setup` escrevia o bloco de instruções do Opus no `AGENTS.md`, lido pelo Codex, e no
|
|
10
|
+
`CLAUDE.md`, lido pelo Claude. A Base fazia o mesmo com o bloco dela. Fora dos blocos, cada projeto
|
|
11
|
+
mantinha à mão as próprias regras nos dois arquivos, e as duas cópias divergiam: na GrandBrasil,
|
|
12
|
+
quatro convenções existiram só no `AGENTS.md` por doze dias, e as sessões do Claude trabalharam sem
|
|
13
|
+
elas.
|
|
14
|
+
|
|
15
|
+
A documentação do Claude Code recomenda, para quem usa as duas ferramentas, um `CLAUDE.md` com a
|
|
16
|
+
linha `@AGENTS.md`. A Base adotou esse formato na ADR 0006. Como o `CLAUDE.md` recebe blocos dos
|
|
17
|
+
dois pacotes, e cada projeto adota as versões deles em momentos diferentes, o Opus precisa seguir
|
|
18
|
+
a mesma regra para que um `setup` não desfaça o do outro.
|
|
19
|
+
|
|
20
|
+
## Decisão
|
|
21
|
+
|
|
22
|
+
O `AGENTS.md` é o único arquivo com instruções. O `opus setup` mantém nele o bloco do Opus e grava
|
|
23
|
+
o `CLAUDE.md` como a linha `@AGENTS.md`, sem marcador.
|
|
24
|
+
|
|
25
|
+
Ao reconciliar o `CLAUDE.md`, o Opus remove só o próprio bloco, quando íntegro. Blocos de outros
|
|
26
|
+
pacotes ficam depois da linha do import, separados por uma linha em branco, até que o pacote dono
|
|
27
|
+
os remova. O texto do projeto fora dos blocos e do import é comparado com o do `AGENTS.md`, com fim
|
|
28
|
+
de linha, espaços no fim das linhas e linhas em branco seguidas normalizados: se for igual, é
|
|
29
|
+
cópia e sai; se for diferente, `setup` e `opus check` preservam o arquivo e pedem para mover as
|
|
30
|
+
instruções para o `AGENTS.md`. Os critérios de bloco, de linha do import e de normalização são os
|
|
31
|
+
da Base, e as mensagens seguem as dela, trocando o comando por `opus setup`.
|
|
32
|
+
|
|
33
|
+
## Consequências
|
|
34
|
+
|
|
35
|
+
- Projeto com instruções só no `CLAUDE.md` precisa movê-las para o `AGENTS.md` antes de o `setup`
|
|
36
|
+
concluir. Por isso a mudança sai numa versão major.
|
|
37
|
+
- Enquanto um projeto usa uma Base anterior à ADR 0006, o `CLAUDE.md` fica com o import e o bloco
|
|
38
|
+
da Base. O conteúdo da Base aparece duas vezes para o Claude, pelo import e pelo bloco, até a
|
|
39
|
+
adoção da Base nova; o arquivo não oscila entre os dois `setup`.
|
|
40
|
+
- Um bloco do Opus editado à mão ou um bloco gerenciado malformado no `CLAUDE.md` são preservados e
|
|
41
|
+
reprovados, como antes.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# ADR 0062 — Listas contidas e texto flexível
|
|
2
|
+
|
|
3
|
+
Data: 2026-10-15
|
|
4
|
+
Status: Aceita
|
|
5
|
+
|
|
6
|
+
## Contexto
|
|
7
|
+
|
|
8
|
+
Descrições sem quebra faziam uma tabela de Habilidades ocupar 92,21rem dentro de
|
|
9
|
+
63,13rem disponíveis. A coluna implícita do grid de resultados do ActionList
|
|
10
|
+
crescia pelo conteúdo; o contêiner da tabela crescia junto e não oferecia sua
|
|
11
|
+
rolagem horizontal. A largura mínima da página não limita a largura dos filhos.
|
|
12
|
+
|
|
13
|
+
## Decisão
|
|
14
|
+
|
|
15
|
+
Table contém sua largura e quebra texto entre palavras por padrão. `overflow-wrap:
|
|
16
|
+
break-word` preserva a largura intrínseca das palavras, evitando que uma descrição
|
|
17
|
+
comprida faça uma coluna como “Inativo” quebrar no meio. Identificadores sem espaços
|
|
18
|
+
podem exigir rolagem interna; `wrap-anywhere` fica disponível como opção explícita.
|
|
19
|
+
Classes explícitas continuam permitindo
|
|
20
|
+
células sem quebra. ActionList limita sua coluna de resultados ao espaço
|
|
21
|
+
recebido e permite encolhimento ao longo da cadeia de flex/grid.
|
|
22
|
+
|
|
23
|
+
`fit` preserva valores compactos sem quebra, como números e datas. O cabeçalho
|
|
24
|
+
de uma coluna declarada pode quebrar entre palavras. Textos flexíveis recebem o
|
|
25
|
+
restante do espaço. Não há redução de tipografia nem ocultação automática de colunas.
|
|
26
|
+
|
|
27
|
+
A barra de filtros pode ocupar mais de uma linha, mantendo a ordem dos controles.
|
|
28
|
+
Uma tabela que ainda exceda a largura disponível rola dentro da lista: em flow,
|
|
29
|
+
no contêiner da tabela; em fill, na região de resultados que também ancora o
|
|
30
|
+
cabeçalho fixo. O rodapé e a toolbar não acompanham essa rolagem.
|
|
31
|
+
|
|
32
|
+
## Alternativas e consequências
|
|
33
|
+
|
|
34
|
+
Largura fixa e repartição igual sacrificariam espaço das colunas textuais mesmo
|
|
35
|
+
quando controles curtos não precisam dele. Ocultar o excesso perderia dados e
|
|
36
|
+
ações. Regras CSS no aplicativo duplicariam o comportamento do pacote.
|
|
37
|
+
|
|
38
|
+
A quebra pode aumentar a altura das linhas. Consumidores com células compostas
|
|
39
|
+
continuam responsáveis por permitir encolhimento dos filhos flex e por declarar
|
|
40
|
+
larguras mínimas somente quando necessárias. Comparativos com colunas mínimas
|
|
41
|
+
explícitas continuam usando rolagem horizontal.
|
|
42
|
+
|
|
43
|
+
## Verificação
|
|
44
|
+
|
|
45
|
+
Testes em Chromium medem contenção, textos longos, filtros, valores compactos e
|
|
46
|
+
rolagem nos modos flow e fill, incluindo a posição do cabeçalho após rolar.
|
|
47
|
+
Os testes estão em `tests/browser/action-list-width.test.tsx` e cobrem também
|
|
48
|
+
palavras curtas ao lado de descrições longas e tokens sem espaços.
|
|
49
|
+
|
|
50
|
+
## Revisão da distribuição entre colunas — 2026-10-15
|
|
51
|
+
|
|
52
|
+
Na validação de Consumo, quatro colunas `fit` ficavam comprimidas enquanto a coluna
|
|
53
|
+
textual recebia cerca de 70% da largura. A largura mínima forçada fazia o navegador
|
|
54
|
+
quebrar títulos mesmo com espaço disponível. Retirar essa restrição reduziu a coluna
|
|
55
|
+
textual para cerca de 38% e acomodou os cabeçalhos numa linha, no mesmo contêiner.
|
|
56
|
+
|
|
57
|
+
Colunas de dados passam a participar da distribuição automática da tabela, considerando
|
|
58
|
+
cabeçalhos e valores. `fit` continua preservando valores sem quebra, mas não impõe
|
|
59
|
+
largura mínima artificial. Cabeçalhos podem quebrar quando o espaço realmente faltar.
|
|
60
|
+
Seleção, ações de linha e células contendo apenas um switch continuam compactas.
|
|
61
|
+
O switch pode ser filho direto ou estar envolvido pelo TooltipTrigger. A regra usa a
|
|
62
|
+
estrutura do controle, sem depender do nome da coluna; células com conteúdo misto
|
|
63
|
+
continuam participando da distribuição natural.
|
|
64
|
+
|
|
65
|
+
Não se distribui largura igualmente nem se mede texto em JavaScript. O algoritmo
|
|
66
|
+
nativo considera o conteúdo e o espaço recebido; a contenção e a rolagem descritas
|
|
67
|
+
acima permanecem. Os testes de navegador cobrem várias colunas numéricas ao lado de
|
|
68
|
+
texto, tanto com espaço suficiente quanto em contêiner estreito, em flow e fill.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# ADR 0063 — Metadados das superfícies em região própria
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-10-15.
|
|
5
|
+
- **Complementa:** ADR 0060.
|
|
6
|
+
- **Substitui parcialmente:** ADR 0045 quanto à posição e função de SurfaceMeta.
|
|
7
|
+
|
|
8
|
+
## Contexto
|
|
9
|
+
|
|
10
|
+
Badges, autoria e datas disputam espaço com o título ou usam o subheading como container.
|
|
11
|
+
A descrição é orientação textual próxima ao heading; metadados precisam de espaçamento
|
|
12
|
+
próprio e quebra de linha sem alterar o tamanho ou o significado do título.
|
|
13
|
+
|
|
14
|
+
## Decisão
|
|
15
|
+
|
|
16
|
+
PageMeta, DrawerMeta, DialogMeta e SurfaceMeta compõem uma faixa opcional após a linha
|
|
17
|
+
que contém título, descrição e ações. Não são headings nem descrições acessíveis dos modais.
|
|
18
|
+
As três primeiras famílias aceitam Meta em Intro ou Header compacto; Surface mantém
|
|
19
|
+
Meta em SurfaceHeader, pois não possui Intro. Meta exige título na mesma composição.
|
|
20
|
+
Dialog em modo de alerta não aceita Meta; informações necessárias à resposta pertencem ao corpo.
|
|
21
|
+
|
|
22
|
+
O intervalo superior é de 0,75rem; itens usam 0,75rem na horizontal e 0,5rem entre linhas.
|
|
23
|
+
A faixa permite quebra, conserva a tipografia dos badges e não insere separadores nem
|
|
24
|
+
busca dados. Sem Meta não há espaço reservado. Uma composição aceita no máximo um Meta.
|
|
25
|
+
As formas curtas de Page e Surface aceitam a prop meta. Fieldset preserva a legend
|
|
26
|
+
restrita a título e mídia decorativa; seus metadados pertencem ao corpo.
|
|
27
|
+
|
|
28
|
+
SurfaceCount preserva o contador ao lado do título e recebe count na forma curta.
|
|
29
|
+
SurfaceMeta deixa de ocupar essa posição: consumidores de contadores explícitos migram
|
|
30
|
+
para SurfaceCount. Consumidores de contexto editorial permanecem em SurfaceMeta.
|
|
31
|
+
|
|
32
|
+
## Alternativas
|
|
33
|
+
|
|
34
|
+
Usar Description conservaria a mistura de prosa e metadados. Colocar wrappers livres no
|
|
35
|
+
Body repetiria espaçamento nos consumidores e afastaria o contexto da identidade. Manter
|
|
36
|
+
SurfaceMeta como contador faria o mesmo nome expressar funções diferentes entre famílias.
|
|
37
|
+
|
|
38
|
+
## Verificação
|
|
39
|
+
|
|
40
|
+
Testes renderizados e checker cobrem posição, unicidade, pai permitido e título obrigatório.
|
|
41
|
+
Contadores permanecem ao lado do título. Testes no navegador conferem intervalo e quebra
|
|
42
|
+
nas famílias, incluindo headers compactos com ações. As evidências pertencem aos arquivos
|
|
43
|
+
`tests/ui/surface-meta.test.tsx`, `tests/browser/surface-meta.test.tsx` e
|
|
44
|
+
`tests/check/check.test.ts`. Publicação e adoção dependem de autorização de entrega.
|
package/docs/adr/README.md
CHANGED
|
@@ -14,3 +14,9 @@ estar documentado na superfície correspondente, sem exigir a reconstrução des
|
|
|
14
14
|
- [ADR 0059 — Subheadings orientam sem carregar regras de negócio](0059-subheadings-orient-without-carrying-business-rules.md).
|
|
15
15
|
|
|
16
16
|
- [ADR 0060 — Composição de superfícies com cabeçalho e intro](0060-surface-composition-separates-chrome-and-intro.md).
|
|
17
|
+
|
|
18
|
+
- [ADR 0061 — O `CLAUDE.md` importa o `AGENTS.md`](0061-claude-md-imports-agents-md.md).
|
|
19
|
+
|
|
20
|
+
- [ADR 0062 — Listas contidas e texto flexível](0062-listas-contidas-e-texto-flexivel.md).
|
|
21
|
+
|
|
22
|
+
- [ADR 0063 — Metadados das superfícies em região própria](0063-metadados-das-superficies.md).
|
package/docs/code-style.md
CHANGED
|
@@ -48,8 +48,12 @@ dinâmica, importada sem fallback ou composta de forma opaca reprova a extraçã
|
|
|
48
48
|
lacunas conhecidas visíveis em vez de produzir um inventário verde e incompleto.
|
|
49
49
|
|
|
50
50
|
Transformações visuais não observáveis e exceções ficam explícitas em `base.json`, usando um
|
|
51
|
-
seletor estável e revisável. `source`, `
|
|
52
|
-
|
|
51
|
+
seletor estável e revisável. `source`, `role` e `text` selecionam o texto pelo conteúdo: a
|
|
52
|
+
declaração vale para toda ocorrência desse texto com esse papel no arquivo e continua válida
|
|
53
|
+
quando linhas entram ou saem acima dela. Um seletor que não encontra o texto reprova a extração,
|
|
54
|
+
porque o texto mudou ou saiu do arquivo. O formato anterior, com `line` no lugar de `text` (ou
|
|
55
|
+
junto dele), ainda é aceito e seleciona exatamente uma entrada naquela linha; `opus copy
|
|
56
|
+
--reanchor` converte esses seletores para o formato por conteúdo. Metadata
|
|
53
57
|
pode complementar a análise, mas nunca sobrescrever uma transformação já observada no JSX —
|
|
54
58
|
`transform: "none"` não mascara `className="uppercase"`. O Opus valida o shape `COPYnnn`; a
|
|
55
59
|
Base instalada é dona do catálogo, dos kinds aceitos e do fundamento de cada regra:
|
|
@@ -63,16 +67,16 @@ Base instalada é dona do catálogo, dos kinds aceitos e do fundamento de cada r
|
|
|
63
67
|
"transforms": [
|
|
64
68
|
{
|
|
65
69
|
"source": "src/account.ts",
|
|
66
|
-
"line": 12,
|
|
67
70
|
"role": "button",
|
|
71
|
+
"text": "Confirmar",
|
|
68
72
|
"transform": "uppercase"
|
|
69
73
|
}
|
|
70
74
|
],
|
|
71
75
|
"exemptions": [
|
|
72
76
|
{
|
|
73
77
|
"source": "src/account.ts",
|
|
74
|
-
"line": 18,
|
|
75
78
|
"role": "label",
|
|
79
|
+
"text": "ABC-123",
|
|
76
80
|
"ruleId": "COPY001",
|
|
77
81
|
"kind": "external-requirement",
|
|
78
82
|
"reason": "Código regulatório exibido na grafia oficial.",
|
|
@@ -145,21 +149,56 @@ exigiria adivinhar espaços continuam reprovando.
|
|
|
145
149
|
|
|
146
150
|
Quando o diagnóstico corresponde a dados reais da aplicação ou a uma mensagem interpolada,
|
|
147
151
|
`copy.dynamic` permite classificar somente aquela superfície sem excluir o arquivo. Cada item
|
|
148
|
-
seleciona
|
|
149
|
-
`
|
|
152
|
+
seleciona o diagnóstico por `source`, `field` e `expression` — o trecho de código que o
|
|
153
|
+
extrator não conseguiu resolver; a mensagem do `opus copy` traz os dois valores prontos para
|
|
154
|
+
copiar —,
|
|
155
|
+
registra `reason` e `reference` auditáveis e usa um destes contratos:
|
|
150
156
|
|
|
151
157
|
- `runtime-data` reconhece nomes, contagens, status ou opções fornecidos em runtime. Nenhuma
|
|
152
158
|
entrada editorial é fabricada;
|
|
153
159
|
- `message-template` exige `role` e `text`. O texto-modelo entra no inventário e passa pela
|
|
154
160
|
política da Base, mas não substitui nem altera o conteúdo renderizado.
|
|
155
161
|
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
No trecho, espaços e quebras de linha viram um espaço só e a vírgula final antes de `)`, `]` ou
|
|
163
|
+
`}` é ignorada, para a âncora sobreviver à reformatação; trechos com mais de 200 caracteres são
|
|
164
|
+
cortados e terminam em `…`. A declaração vale para toda ocorrência do mesmo trecho no mesmo
|
|
165
|
+
campo do arquivo e não depende da linha em que ele está.
|
|
166
|
+
|
|
167
|
+
As declarações aparecem em `dynamicSurfaces` no inventário, com as linhas atuais de cada
|
|
168
|
+
ocorrência. Se o código mudar e o seletor deixar de encontrar o trecho, `opus copy` falha e lista,
|
|
169
|
+
numa execução, todas as declarações quebradas, cada uma com o arquivo, o campo e os trechos desse
|
|
170
|
+
campo que ainda não têm declaração. Assim, a classificação permanece
|
|
158
171
|
estreita e revisável, sem transformar metadata em uma exclusão silenciosa. O mecanismo aceita
|
|
159
172
|
somente diagnósticos de conteúdo; incerteza estrutural, `className`, `style`, transformação ou
|
|
160
173
|
modo de renderização continua bloqueante. Superfície vazia também não pode ser reclassificada
|
|
161
174
|
como dado de runtime.
|
|
162
175
|
|
|
176
|
+
Declarações escritas antes da versão 29.0.0 usam `line` no lugar de `expression` (ou de `text`,
|
|
177
|
+
nas exceções e transformações) e quebram sempre que alguém edita o arquivo acima delas. Elas
|
|
178
|
+
continuam aceitas, selecionam exatamente um alvo naquela linha e são aplicadas antes das
|
|
179
|
+
declarações por conteúdo, para que uma declaração pontual não seja coberta por uma geral; o
|
|
180
|
+
`opus copy` avisa quantas restam. Para convertê-las, rode `opus copy --reanchor`. O comando
|
|
181
|
+
agrupa as declarações por arquivo e campo (em `copy.dynamic`) ou por arquivo, papel e texto
|
|
182
|
+
(nas exceções e transformações), grava o `base.json` e regenera o inventário:
|
|
183
|
+
|
|
184
|
+
- um grupo só é convertido quando tem exatamente uma declaração para cada alvo. Assim a âncora
|
|
185
|
+
por conteúdo cobre os mesmos alvos que as âncoras por linha cobriam. Se o mesmo texto aparece
|
|
186
|
+
mais vezes do que foi declarado, ou se há um diagnóstico do campo sem declaração, o grupo
|
|
187
|
+
continua por linha e aparece no relatório;
|
|
188
|
+
- dentro do grupo, declarações e alvos são pareados em ordem de linha. Quando o arquivo mudou e
|
|
189
|
+
as âncoras quebraram, o comando lista cada declaração que mudou de linha para revisão no diff;
|
|
190
|
+
- declarações idênticas que passariam a selecionar o mesmo conteúdo viram uma só;
|
|
191
|
+
- duas declarações com motivos diferentes para o mesmo conteúdo continuam por linha, já
|
|
192
|
+
corrigida, porque um seletor por conteúdo cobriria as duas com um único motivo. Para
|
|
193
|
+
convertê-las, unifique o motivo ou mantenha a âncora por linha;
|
|
194
|
+
- os seletores gravados precisam passar na extração do `opus copy`; o que não dá para ancorar com
|
|
195
|
+
segurança fica como está e aparece no relatório.
|
|
196
|
+
|
|
197
|
+
O `--reanchor` não avalia a política de copy da Base. Depois dele, rode `opus copy --check` e
|
|
198
|
+
`base copy check`. Na revisão de uma declaração por conteúdo, vale olhar `dynamicSurfaces[].lines`
|
|
199
|
+
no diff do inventário: uma lista que cresce indica que um trecho genérico, como `title` ou
|
|
200
|
+
`count`, passou a cobrir uma ocorrência nova, que pode ter outra origem.
|
|
201
|
+
|
|
163
202
|
Um `opus copy --check` verde **não significa que toda a copy do produto foi coberta**. Ficam
|
|
164
203
|
fora, deliberadamente:
|
|
165
204
|
|
package/docs/protocol.md
CHANGED
|
@@ -679,7 +679,7 @@ O acesso do sistema é **opt-in por action** e negado por padrão. Sem usuário,
|
|
|
679
679
|
`isSystemActor(ctx)` responde se o ator é o sistema. Ele consulta um registro interno dos contextos que o runtime criou, e não a provenance. Como o sistema não detém permissões, um `authorize` que delega a `ctx.can` o aceita de forma explícita, numa closure — a DSL em string não expressa isso, e `ctx.provenance` não serve como teste de sistema, porque o chamador de `runtime.execute` pode preenchê-la:
|
|
680
680
|
|
|
681
681
|
```ts
|
|
682
|
-
authorize: (ctx) => isSystemActor(ctx) || ctx.can('
|
|
682
|
+
authorize: (ctx) => isSystemActor(ctx) || ctx.can('ledger:close')
|
|
683
683
|
```
|
|
684
684
|
|
|
685
685
|
`requires` continua declarativo; o manifest projeta `automatable` ao lado de `permission`. O audit registra `actor: { id: null, type: 'system' }`. Ver ADR 0028.
|
package/docs/releasing.md
CHANGED
|
@@ -18,6 +18,13 @@ confere essa entrada só DEPOIS do bump, então esquecê-la aborta a release com
|
|
|
18
18
|
alterado — e a tentativa seguinte para na guarda de árvore limpa. Para recuperar, desfaça o bump
|
|
19
19
|
(`git checkout -- package.json`), escreva a entrada, commite e rode de novo.
|
|
20
20
|
|
|
21
|
+
Uma entrada que já está na `origin/main` não muda mais: quem consome o pacote lê o changelog como
|
|
22
|
+
guia de migração, e em 10/09/2026 uma formatação avulsa reescreveu entradas publicadas e mudou o
|
|
23
|
+
sentido de uma delas. Para corrigir uma informação publicada, registre a correção numa entrada
|
|
24
|
+
nova, na próxima versão. A entrada da versão em preparo, enquanto não chega à `main`, pode ser
|
|
25
|
+
ajustada livremente. O pre-push (`.githooks/pre-push.d/01-changelog`) e o `pnpm release` reprovam
|
|
26
|
+
a alteração de uma seção publicada; para conferir antes, rode `pnpm changelog:check` na raiz.
|
|
27
|
+
|
|
21
28
|
Os comandos rodam em `packages/opus`; o `package.json` da raiz não tem `release`.
|
|
22
29
|
|
|
23
30
|
```bash
|
package/package.json
CHANGED
|
@@ -24,7 +24,9 @@ artefatos de agentes fica em `base.json`; cada app Opus mantém seu marcador `op
|
|
|
24
24
|
e operá-los por `opus seed`; não criar comandos de seed paralelos nem reset implícito.
|
|
25
25
|
- Regenerar o inventário com `opus copy` quando mudar copy em contrato ou componente Opus
|
|
26
26
|
mapeado; o Opus classifica os papéis semânticos e a política universal de `@softize/base`
|
|
27
|
-
valida o conteúdo.
|
|
27
|
+
valida o conteúdo. O inventário também guarda o hash de todo arquivo JS/TS do escopo, mesmo sem
|
|
28
|
+
copy, como os scripts em `scripts/*.mjs`; alterar qualquer um deles também exige `opus copy`,
|
|
29
|
+
e o pre-push reprova o inventário desatualizado.
|
|
28
30
|
- Rodar `opus check`, `opus copy --check` e os gates do projeto depois de alterar actions,
|
|
29
31
|
bindings ou versão do SDK.
|
|
30
32
|
- Quando a default branch tiver adotado uma versão diferente da worktree, reconciliar a
|
|
@@ -65,7 +65,7 @@ existentes, mantendo navegação observável e componentes reutilizáveis sem la
|
|
|
65
65
|
relativa do Tailwind. Reservar `px` a hairlines e compensações presas à geometria da borda,
|
|
66
66
|
com justificativa e cobertura explícitas.
|
|
67
67
|
11. Em uma página centrada em coleção, compor `Surface + ActionList`: título e criação ficam em
|
|
68
|
-
extremos opostos do `SurfaceHeader`; a criação usa botão textual `
|
|
68
|
+
extremos opostos do `SurfaceHeader`; a criação usa botão textual `sm`, sem ícone, com
|
|
69
69
|
`Criar recurso`. Busca, filtros, atualização, estados e paginação permanecem no `ActionList`.
|
|
70
70
|
Reservar `toolbarActions` a operações ligadas ao recorte atual.
|
|
71
71
|
12. Evoluir um pattern compartilhado apenas quando a recorrência e o contrato estiverem claros.
|
|
@@ -89,10 +89,12 @@ existentes, mantendo navegação observável e componentes reutilizáveis sem la
|
|
|
89
89
|
Rodar `opus check`, testes focados, typecheck e build da superfície. Se a interface alterou
|
|
90
90
|
copy em contrato ou componente Opus mapeado, regenerar com `opus copy` e executar
|
|
91
91
|
`base copy check`. Quando uma superfície mapeada recebe dados da aplicação, usar
|
|
92
|
-
`copy.dynamic` com
|
|
93
|
-
editorial; `message-template` com `role` e
|
|
92
|
+
`copy.dynamic` com `field` e `expression` copiados do diagnóstico, motivo e referência:
|
|
93
|
+
`runtime-data` para valores sem autoria editorial; `message-template` com `role` e
|
|
94
|
+
texto-modelo para mensagens interpoladas. Não usar `line` em declaração nova. Não excluir
|
|
94
95
|
o arquivo inteiro nem contornar o diagnóstico com `aria-label` paralelo. Revisar cada declaração
|
|
95
|
-
dinâmica como fronteira de cobertura, mesmo com os gates verdes
|
|
96
|
+
dinâmica como fronteira de cobertura, mesmo com os gates verdes, inclusive quando
|
|
97
|
+
`dynamicSurfaces[].lines` cresce no diff do inventário.
|
|
96
98
|
Inspecionar visualmente a rota real e validar navegação por URL quando aplicável.
|
|
97
99
|
|
|
98
100
|
## Limites
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
outra em `PageShell` com navegação contextual acima de `Page > PageHeader + PageBody`, garantindo
|
|
8
8
|
exatamente um `PageTitle` no header, e uma coleção nomeada com
|
|
9
9
|
`Surface > SurfaceHeader + SurfaceBody > ActionList`. Provar que criação fica em
|
|
10
|
-
`SurfaceActions`, no extremo oposto ao título, como botão textual `
|
|
10
|
+
`SurfaceActions`, no extremo oposto ao título, como botão textual `sm` sem ícone e com
|
|
11
11
|
`Criar recurso`, enquanto uma operação dependente do recorte usa `toolbarActions`; incluir
|
|
12
12
|
`ActionFilterBar` separado do renderer, `ItemGroup` para
|
|
13
13
|
uma coleção secundária e um `ActionFormDialog`; provar teto padrão de `80rem`, hierarquia por
|
|
@@ -84,3 +84,12 @@ da label, duplicação entre hint/help e perda de `aria-describedby` quando apar
|
|
|
84
84
|
IntroActions, nenhum header vazio na Page e transição de loading para conteúdo sem título duplicado.
|
|
85
85
|
- Reprovar intro depois de texto, título simultâneo em header e intro, ações da superfície no título
|
|
86
86
|
ou adaptação de Pane para que ele volte a possuir anatomia visual.
|
|
87
|
+
|
|
88
|
+
## Metadados e contadores
|
|
89
|
+
|
|
90
|
+
- Execução: compor um detalhe com título, descrição e badges em PageMeta, DrawerMeta e DialogMeta;
|
|
91
|
+
conferir a faixa separada em Header compacto e Intro. Em Surface, conferir que SurfaceCount
|
|
92
|
+
fica na linha do título e SurfaceMeta abaixo dela. Migrar um contador antigo e uma descrição
|
|
93
|
+
antiga sem alterar suas funções; provar a equivalência das formas curtas com `meta`.
|
|
94
|
+
- Reprova: contador em SurfaceMeta, metadados em Description, dois Meta, Meta sem título,
|
|
95
|
+
Meta em fieldset ou DialogMeta em alerta.
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
recuperação como botão `outline` textual. Estados de seção ou coleção continuam em `DataState`,
|
|
37
37
|
`ActionView`, `ActionList` ou `Alert`; não elevar uma falha parcial a estado da página.
|
|
38
38
|
- `Surface` delimita uma região e segue a anatomia `Surface > SurfaceHeader (SurfaceMedia,
|
|
39
|
-
SurfaceTitle, SurfaceDescription, SurfaceMeta, SurfaceActions) + SurfaceBody + SurfaceFooter`.
|
|
40
|
-
Os slots nunca ficam soltos. `title`, `description`, `count`, `media` e `actions` são a abreviação
|
|
39
|
+
SurfaceTitle, SurfaceCount, SurfaceDescription, SurfaceMeta, SurfaceActions) + SurfaceBody + SurfaceFooter`.
|
|
40
|
+
Os slots nunca ficam soltos. `title`, `description`, `count`, `meta`, `media` e `actions` são a abreviação
|
|
41
41
|
para o caso direto e não podem ser misturados ao header explícito. Em `level={1}`, ações da
|
|
42
42
|
coleção ficam no extremo oposto ao título; a criação usa botão textual `sm`, sem ícone, com
|
|
43
43
|
`Criar recurso`.
|
|
@@ -45,6 +45,14 @@ SurfaceTitle, SurfaceDescription, SurfaceMeta, SurfaceActions) + SurfaceBody + S
|
|
|
45
45
|
hierarquia semântica do heading. `Surface framed` aceita `layout="sectioned"`; declare
|
|
46
46
|
`SurfaceBody flush` quando o filho direto já possui recuo interno, como `DetailGroup` com
|
|
47
47
|
divisores, lista ou tabela. `as="fieldset"` cria a `legend` nativa sem variante de moldura.
|
|
48
|
+
- `PageMeta`, `DialogMeta` e `DrawerMeta` recebem badges, datas e autoria em faixa própria
|
|
49
|
+
após título, descrição e ações, dentro de Header compacto ou Intro da mesma família.
|
|
50
|
+
`SurfaceMeta` ocupa essa faixa em `SurfaceHeader`; `SurfaceCount` mantém o contador na linha
|
|
51
|
+
do título. Ao migrar, conferir manualmente os antigos `SurfaceMeta`: contadores passam a
|
|
52
|
+
`SurfaceCount`, frases de orientação a `SurfaceDescription`, e metadados permanecem em Meta.
|
|
53
|
+
Cada composição aceita um Meta e exige título. Page e Surface aceitam `meta` na forma curta;
|
|
54
|
+
fieldset e Dialog em `mode="alert"` não aceitam Meta. Informações necessárias à decisão
|
|
55
|
+
permanecem no corpo ou junto à ação correspondente.
|
|
48
56
|
- Uma página centrada em coleção compõe `Surface + ActionList`. O `SurfaceHeader` recebe título e
|
|
49
57
|
criação; o `ActionList` mantém busca, filtros, atualização, resultados, estados e paginação.
|
|
50
58
|
`toolbarActions` fica reservado a operações que dependem do recorte atual.
|
|
@@ -52,7 +52,8 @@ o código não sustenta.
|
|
|
52
52
|
|
|
53
53
|
Executar `node scripts/audit-docs.mjs "$(git rev-parse --show-toplevel)"` a partir do diretório
|
|
54
54
|
desta skill e, depois, os testes do renderer e do catálogo, typecheck, `opus check` e
|
|
55
|
-
`opus copy --check`.
|
|
55
|
+
`opus copy --check`. No repositório do Opus, o teste `tests/scripts/example-language.test.ts`
|
|
56
|
+
reprova identificadores com palavra em português nos exemplos e nas fontes; rode-o também. Conferir
|
|
56
57
|
que todos os previews renderizam, que cada API pública documentada possui sua própria referência,
|
|
57
58
|
que nenhum arquivo publicado ficou órfão e que links e redirects chegam à página esperada. Fazer uma
|
|
58
59
|
passada visual nas páginas alteradas e registrar qualquer limitação que o gate automático não cubra.
|
|
@@ -40,6 +40,13 @@ genérica.
|
|
|
40
40
|
- Depois do código, explicar somente efeitos que não sejam óbvios pela leitura: default aplicado,
|
|
41
41
|
estado controlado, ação automática, limite ou consequência.
|
|
42
42
|
- Usar preview para comportamento visual e bloco de código para integração sem palco executável.
|
|
43
|
+
- Escrever o código dos exemplos em inglês, como o resto do código: variáveis, funções, campos,
|
|
44
|
+
nomes de action, domínios, eventos, schedules, permissões e caminhos de arquivo
|
|
45
|
+
(`ledgerCloseContract`, `ledger.close`, `ledger:close`, `design/scenarios/orders.ts`). Isso vale
|
|
46
|
+
também para o código em crase no meio da prosa. O texto que a pessoa vê — `label`, mensagens,
|
|
47
|
+
descrições, conteúdo JSX — e os comentários continuam em pt-BR. Um exemplo fictício não tem
|
|
48
|
+
vocabulário de domínio estabelecido, então a exceção de domínio das instruções do projeto não se
|
|
49
|
+
aplica a ele.
|
|
43
50
|
|
|
44
51
|
## Famílias e referência
|
|
45
52
|
|
|
@@ -74,6 +81,8 @@ Para cada título, parágrafo, item, exemplo e célula de tabela, verificar:
|
|
|
74
81
|
8. O texto ao redor do exemplo explica intenção e comportamento, sem narrar cada linha do código?
|
|
75
82
|
9. O título permite localizar a informação pela tarefa, inclusive por link direto?
|
|
76
83
|
10. Pontuação, capitalização, concordância e paralelismo estão consistentes?
|
|
84
|
+
11. Os identificadores do exemplo e do código em crase estão em inglês, e o texto exibido à pessoa,
|
|
85
|
+
em pt-BR?
|
|
77
86
|
|
|
78
87
|
Ao terminar cada página, reler a sequência inteira. Linhas corretas isoladamente ainda podem formar
|
|
79
88
|
uma página repetitiva, invertida ou sem progressão.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<!-- language-exempt-file: o caso de avaliação descreve de propósito um exemplo com identificadores em português. -->
|
|
2
|
+
|
|
1
3
|
# Avaliações
|
|
2
4
|
|
|
3
5
|
## Deve disparar
|
|
@@ -32,3 +34,9 @@ Exigir inventário explícito, leitura linha por linha, correção na fonte can
|
|
|
32
34
|
previews, typecheck, gates de copy e confirmação de que não restaram páginas órfãs. Reprovar se a
|
|
33
35
|
execução se limitar às páginas mais longas, fizer apenas busca por padrões ou declarar cobertura
|
|
34
36
|
total sem listar o universo revisado.
|
|
37
|
+
|
|
38
|
+
Num exemplo de agendamento com `caixaFecharContract`, a action `caixa.fechar`, a permissão
|
|
39
|
+
`caixa:fechar` e o rótulo `Fechar caixa`, pedir a revisão da página sem apontar o problema.
|
|
40
|
+
Aprovar somente quando identificadores, action, domínio e permissão passarem para o inglês, o
|
|
41
|
+
rótulo continuar em pt-BR e o gate de idioma passar. Reprovar se o rótulo for traduzido ou se a
|
|
42
|
+
exceção de vocabulário de domínio for usada para manter o exemplo fictício em português.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Permissão de build scripts (o pnpm bloqueia por default): o postinstall do
|
|
2
|
-
# @softize/opus roda o `opus setup` (pin + bloco gerenciado do
|
|
2
|
+
# @softize/opus roda o `opus setup` (pin + bloco gerenciado do AGENTS.md) a cada
|
|
3
3
|
# install; o esbuild (vite) compila o binário nativo.
|
|
4
4
|
allowBuilds:
|
|
5
5
|
'@softize/opus': true
|
package/src/core/system-actor.ts
CHANGED
|
@@ -17,7 +17,7 @@ const systemContexts = new WeakSet<object>()
|
|
|
17
17
|
/**
|
|
18
18
|
* Diz se a action está executando como o sistema: disparada por um schedule, ou no job que ele
|
|
19
19
|
* enfileirou, sem usuário. Use no `authorize` de uma action `automatable` para aceitar o sistema
|
|
20
|
-
* de forma explícita: `authorize: (ctx) => isSystemActor(ctx) || ctx.can('
|
|
20
|
+
* de forma explícita: `authorize: (ctx) => isSystemActor(ctx) || ctx.can('ledger:close')`.
|
|
21
21
|
* Passe o próprio `ctx` recebido: uma cópia, como `{ ...ctx }`, não é reconhecida.
|
|
22
22
|
*/
|
|
23
23
|
export function isSystemActor(ctx: ActionContext): boolean {
|
package/src/core/types.ts
CHANGED
|
@@ -714,7 +714,7 @@ export interface ListColumnSpec {
|
|
|
714
714
|
/** Header clicável (asc ↔ desc). Convenção: a UI escreve `sort: '<key>:<dir>'` no
|
|
715
715
|
* input; o handler implementa o orderBy. */
|
|
716
716
|
sortable?: boolean
|
|
717
|
-
/**
|
|
717
|
+
/** Preserva valores sem quebra; a largura considera também o cabeçalho e o espaço disponível. */
|
|
718
718
|
fit?: boolean
|
|
719
719
|
/** Nasce oculta (candidata ao column picker). */
|
|
720
720
|
hidden?: boolean
|