@trismegisto/spine 2.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.
Files changed (55) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +207 -0
  3. package/fesm2022/trismegisto-spine-audit.mjs +1299 -0
  4. package/fesm2022/trismegisto-spine-audit.mjs.map +1 -0
  5. package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs +37 -0
  6. package/fesm2022/trismegisto-spine-auto-service-auto-service-audit.component-CCiz-q8o.mjs.map +1 -0
  7. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs +51 -0
  8. package/fesm2022/trismegisto-spine-auto-service-auto-service-client-picker.component-Z0wCANF6.mjs.map +1 -0
  9. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs +595 -0
  10. package/fesm2022/trismegisto-spine-auto-service-auto-service-client.component-BYkUOwWL.mjs.map +1 -0
  11. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs +357 -0
  12. package/fesm2022/trismegisto-spine-auto-service-auto-service-groups.component-CqIVe2LU.mjs.map +1 -0
  13. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs +477 -0
  14. package/fesm2022/trismegisto-spine-auto-service-auto-service.component-B5tyJ2zY.mjs.map +1 -0
  15. package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs +238 -0
  16. package/fesm2022/trismegisto-spine-auto-service-home.component-vl3BPFnk.mjs.map +1 -0
  17. package/fesm2022/trismegisto-spine-auto-service.mjs +154 -0
  18. package/fesm2022/trismegisto-spine-auto-service.mjs.map +1 -0
  19. package/fesm2022/trismegisto-spine-graphql.mjs +347 -0
  20. package/fesm2022/trismegisto-spine-graphql.mjs.map +1 -0
  21. package/fesm2022/trismegisto-spine-layout.mjs +2848 -0
  22. package/fesm2022/trismegisto-spine-layout.mjs.map +1 -0
  23. package/fesm2022/trismegisto-spine-modal.mjs +141 -0
  24. package/fesm2022/trismegisto-spine-modal.mjs.map +1 -0
  25. package/fesm2022/trismegisto-spine-notification.mjs +122 -0
  26. package/fesm2022/trismegisto-spine-notification.mjs.map +1 -0
  27. package/fesm2022/trismegisto-spine-routing.mjs +398 -0
  28. package/fesm2022/trismegisto-spine-routing.mjs.map +1 -0
  29. package/fesm2022/trismegisto-spine-shell.mjs +409 -0
  30. package/fesm2022/trismegisto-spine-shell.mjs.map +1 -0
  31. package/fesm2022/trismegisto-spine-side-panel.mjs +142 -0
  32. package/fesm2022/trismegisto-spine-side-panel.mjs.map +1 -0
  33. package/fesm2022/trismegisto-spine.mjs +2574 -0
  34. package/fesm2022/trismegisto-spine.mjs.map +1 -0
  35. package/package.json +94 -0
  36. package/types/trismegisto-spine-audit.d.ts +948 -0
  37. package/types/trismegisto-spine-audit.d.ts.map +1 -0
  38. package/types/trismegisto-spine-auto-service.d.ts +110 -0
  39. package/types/trismegisto-spine-auto-service.d.ts.map +1 -0
  40. package/types/trismegisto-spine-graphql.d.ts +72 -0
  41. package/types/trismegisto-spine-graphql.d.ts.map +1 -0
  42. package/types/trismegisto-spine-layout.d.ts +1054 -0
  43. package/types/trismegisto-spine-layout.d.ts.map +1 -0
  44. package/types/trismegisto-spine-modal.d.ts +68 -0
  45. package/types/trismegisto-spine-modal.d.ts.map +1 -0
  46. package/types/trismegisto-spine-notification.d.ts +62 -0
  47. package/types/trismegisto-spine-notification.d.ts.map +1 -0
  48. package/types/trismegisto-spine-routing.d.ts +205 -0
  49. package/types/trismegisto-spine-routing.d.ts.map +1 -0
  50. package/types/trismegisto-spine-shell.d.ts +143 -0
  51. package/types/trismegisto-spine-shell.d.ts.map +1 -0
  52. package/types/trismegisto-spine-side-panel.d.ts +66 -0
  53. package/types/trismegisto-spine-side-panel.d.ts.map +1 -0
  54. package/types/trismegisto-spine.d.ts +1161 -0
  55. package/types/trismegisto-spine.d.ts.map +1 -0
package/LICENSE ADDED
@@ -0,0 +1,56 @@
1
+ Hermes License 1.0
2
+
3
+ Copyright (c) 2026 Lucas Ribeiro. All rights reserved except as granted below.
4
+
5
+ 1. Use. You may, free of charge, install and use this software (the "Library"),
6
+ unmodified, for any purpose, including commercial purposes.
7
+
8
+ 2. Applications. You may include the unmodified Library in an application or
9
+ service you build and distribute or make that application available to others
10
+ (for example, a compiled web application bundle, a container image or an
11
+ installed program), provided the Library is not offered as a separate,
12
+ standalone component and this license notice is kept with it.
13
+
14
+ 3. No modification. You may not modify, adapt, translate or create derivative
15
+ works of the Library.
16
+
17
+ 4. No redistribution. Except as allowed in section 2, you may not publish,
18
+ redistribute, sublicense, sell or otherwise make available the Library —
19
+ including as a package in a public or private registry, a fork or a copy of
20
+ its source code.
21
+
22
+ 5. Notice. You must keep this license and the copyright notice with every copy
23
+ of the Library.
24
+
25
+ 6. No warranty. The Library is provided "as is", without warranty of any kind,
26
+ express or implied. In no event shall the author be liable for any claim,
27
+ damages or other liability arising from the use of the Library.
28
+
29
+ 7. Third-party components. Some files in the Library are, or are derived from,
30
+ third-party software and fonts. They are identified in the NOTICE files, in
31
+ the LICENSES folders and in the font license files shipped with the package,
32
+ and remain under their own licenses. Nothing in this license limits the
33
+ rights those licenses grant for those parts.
34
+
35
+ ---
36
+
37
+ Licença Hermes 1.0 (tradução de referência; em caso de divergência vale o texto em inglês)
38
+
39
+ 1. Uso. Você pode, gratuitamente, instalar e usar esta biblioteca, sem modificações,
40
+ para qualquer finalidade, inclusive comercial.
41
+ 2. Aplicações. Você pode incluir a biblioteca, sem modificações, numa aplicação ou
42
+ serviço seu e distribuir ou disponibilizar essa aplicação (por exemplo, o bundle de
43
+ um app web, uma imagem de container ou um programa instalado), desde que a biblioteca
44
+ não seja oferecida como componente avulso e este aviso de licença a acompanhe.
45
+ 3. Sem modificação. Você não pode modificar, adaptar, traduzir nem criar obras
46
+ derivadas da biblioteca.
47
+ 4. Sem redistribuição. Fora o permitido no item 2, você não pode publicar, redistribuir,
48
+ sublicenciar, vender ou disponibilizar a biblioteca — inclusive como pacote num
49
+ registry público ou privado, fork ou cópia do código-fonte.
50
+ 5. Aviso. Mantenha esta licença e o aviso de copyright em todas as cópias.
51
+ 6. Sem garantia. A biblioteca é fornecida "como está", sem garantia de qualquer tipo.
52
+ 7. Componentes de terceiros. Alguns arquivos da biblioteca são, ou derivam de, software
53
+ e fontes de terceiros. Eles estão identificados nos arquivos NOTICE, nas pastas
54
+ LICENSES e nos arquivos de licença das fontes que acompanham o pacote, e continuam
55
+ sob as licenças originais. Nada nesta licença limita os direitos que elas concedem
56
+ sobre essas partes.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # @trismegisto/spine
2
+
3
+ Shell de aplicação pronto sobre o `@trismegisto/angular`: cabeçalho, menu lateral, área de trabalho em abas
4
+ (`hm-workspace`), roteamento hierárquico a partir da árvore de rotas do servidor de autorização, telas de
5
+ login/estado (sem permissão, bloqueado, carregando), modal, painel lateral e notificações por serviço,
6
+ configurações (tema, família, densidade, fonte, atalhos), tour de boas-vindas, novidades e documentação por
7
+ tela.
8
+
9
+ Na cadeia de camadas (`tokens ← icons ← primitives ← core ← angular ← maps · charts · spine`) é a ponta: monta
10
+ peças grandes sobre o `@trismegisto/angular` e é o que os apps da organização usam como esqueleto. Ao contrário
11
+ dos outros pacotes, é acoplado à autenticação (`@orfeu/angular` ≥ 0.9.9, OIDC + PKCE contra o Argos): serve a
12
+ apps que se autenticam nesse servidor. O app e o spine precisam usar a **mesma** cópia do `@orfeu/angular` — com o
13
+ app ainda no SDK antigo (`@caronte-sdk/angular`) os serviços seriam outros e o shell quebraria
14
+ (`NullInjectorError` em `AUTH_CONFIG` ou uma segunda sessão); migre os dois juntos.
15
+
16
+ ## Instalação
17
+
18
+ ```bash
19
+ npm install @trismegisto/spine @trismegisto/angular @trismegisto/core @trismegisto/tokens @trismegisto/primitives @trismegisto/icons
20
+ ```
21
+
22
+ Peers: os cinco pacotes base do Hermes (mesma versão), `@angular/core`, `common` e `router` ≥ 21, `rxjs` e
23
+ `@orfeu/angular` (`^0.9.9`). Só para o ponto `@trismegisto/spine/graphql`: `@apollo/client`, `apollo-angular`,
24
+ `graphql` e `graphql-ws` (opcionais). O CSS é o mesmo dos pacotes base (`tokens.css` e `core.css` no
25
+ `angular.json`, ver o [README do `@trismegisto/angular`](../angular/README.md)).
26
+
27
+ ## Configuração do app
28
+
29
+ ```ts
30
+ import { ApplicationConfig } from '@angular/core';
31
+ import { provideRouter } from '@angular/router';
32
+ import { provideAuth } from '@orfeu/angular/core';
33
+ import { provideUi, provideSpineNews } from '@trismegisto/spine';
34
+ import { APP_ROUTES, provideShell } from '@trismegisto/spine/shell';
35
+ import { components } from './features/features.routes';
36
+ import { environment } from './environments/environment';
37
+ import packageInfo from '../../package.json';
38
+
39
+ export const appConfig: ApplicationConfig = {
40
+ providers: [
41
+ provideUi({ clientId: environment.authorizationServer.clientId, appName: 'Meu App' }),
42
+ provideRouter(APP_ROUTES),
43
+ provideAuth(environment.authorizationServer),
44
+ provideShell({ appComponents: components, packageInfo }),
45
+ // provideSpineNews([...]), // novidades exibidas uma vez por pessoa
46
+ ],
47
+ };
48
+ ```
49
+
50
+ - **`provideUi(config)`** registra o catálogo de ícones inteiro (o shell usa ícones de vários grupos), aplica
51
+ o tema no `<body>` e usa `clientId` como prefixo de **todas** as chaves salvas (tema, menu lateral, abas):
52
+ apps diferentes na mesma origem não misturam preferências. Opções: `clientId`, `appName` (nome ao lado do
53
+ logo no cabeçalho), `logo`, `showAppName` e `favicon` (ver "Logo e favicon" abaixo), `technicalDocs` (mostra a
54
+ especificação técnica das telas; padrão `isDevMode()`).
55
+ - **`APP_ROUTES`** traz login, callback, saída e as rotas privadas sob o `spine-layout`
56
+ (`LayoutComponent`). O `/callback` usa o `handleCallback()` do `@orfeu/angular`: confere state/verifier, volta
57
+ para a URL pedida antes do login e, no `login_required` da reautorização silenciosa, segue sozinho para o login
58
+ interativo. Callback recusado nunca desloga: com sessão viva volta para a URL de retorno; sem sessão mostra a
59
+ página de erro com "Entrar novamente". O `spine-layout` traz o **aviso de conexão** (`spine-connection-banner`,
60
+ entre o cabeçalho e o corpo): `hm-alert` em faixa quando o `connectionState$` está `offline`, `reconnecting` ou
61
+ `reauthorizing`, e "Entrar novamente" (sem deslogar) quando o `reauthorizationRequired$` pede — textos em
62
+ `SpineMessages.session`. O componente raiz do app só precisa de um `<router-outlet />`: o tema já está no
63
+ `<body>`, então não use `hermesTheme` por cima.
64
+ - **`provideShell({ appComponents, packageInfo })`** liga cada tela do app a um `id` da árvore de rotas — o
65
+ **`router_id`** da tela (`web.router` do client, o `router_id` do nó 'page' da view), nunca o `web.routes.route_id`.
66
+ Tela de template (auto-serviço) registra `source_template_router_id` (o router do template, igual em todo client
67
+ vinculado). O título e a **descrição** da tela (`web.router.description`, editada no Argos) aparecem na barra da
68
+ página (`spine-page-bar`): a tela não repete título/descrição internos.
69
+
70
+ ```ts
71
+ import { ComponentRoute } from '@trismegisto/spine/routing';
72
+
73
+ export const components: ComponentRoute[] = [
74
+ {
75
+ id: '<router_id da tela>',
76
+ load: () => import('./dashboard/dashboard.component').then((m) => m.DashboardComponent),
77
+ document: { load: () => import('./dashboard/README.md').then((m) => m.default) }, // opcional
78
+ },
79
+ ];
80
+ ```
81
+
82
+ ## Logo e favicon
83
+
84
+ O spine não traz marca nenhuma: o logo do cabeçalho e o favicon são arquivos do app.
85
+
86
+ ```ts
87
+ provideUi({
88
+ clientId: environment.authorizationServer.clientId,
89
+ appName: 'Meu App',
90
+ // Omitido = convenção 'assets/images/logo.svg' (arquivo em src/assets/images/logo.svg).
91
+ logo: { light: 'assets/images/logo.svg', dark: 'assets/images/logo-dark.svg' },
92
+ favicon: 'assets/favicon.ico',
93
+ }),
94
+ ```
95
+
96
+ | Opção | Padrão | O que faz |
97
+ | --- | --- | --- |
98
+ | `logo` | `'assets/images/logo.svg'` | String (os dois temas), `{ light, dark?, alt? }` (`dark` no tema escuro) ou `false` (sem imagem). SVG, PNG, WebP… — qualquer imagem que o navegador abra |
99
+ | `showAppName` | `true` | Mostra `appName` ao lado do logo. Com `false`, o nome só aparece quando não há logo visível |
100
+ | `favicon` | — | Atualiza (ou cria) o `<link rel="icon">` no bootstrap. Sem ele, vale o do `index.html` (`assets/favicon.ico` nos apps) |
101
+
102
+ - **Onde pôr os arquivos:** `src/assets/images/logo.svg` (e `logo-dark.svg`, opcional) e `src/assets/favicon.ico`,
103
+ com `src/assets` publicado em `assets/` no `angular.json`. O `href` é relativo ao `<base href>`.
104
+ - **Sem arquivo / erro:** imagem que não carrega (404) some e fica só o nome — sem ícone quebrado; o console mostra só
105
+ o 404 do navegador. A variante `dark` que falha cai para a `light`. Para não ter nem o 404, use `logo: false`.
106
+ - **Tamanho e contraste:** altura fixa de 28px (`--hm-icon-xl`), largura proporcional com teto (6× a altura; 4× no
107
+ celular). O fundo do cabeçalho é a banda escura (`--hm-navbar-surface`) **nos dois temas**: o logo precisa ser
108
+ legível sobre ela (versão clara/branca); `dark` serve para um ajuste fino no tema escuro.
109
+ - **Acessibilidade:** a marca é um link para a primeira rota da view (dica `SpineMessages.header.home`). Texto
110
+ alternativo = `logo.alt`; sem ele, vazio quando o nome está ao lado (o leitor de tela não repete) e o `appName`
111
+ quando o nome está escondido.
112
+ - **Marca em componente:** `{ provide: SPINE_BRAND, useValue: MarcaComponent }` (`@trismegisto/spine/layout`) tem
113
+ prioridade sobre a imagem (ex.: SVG inline com `currentColor`). Ele fica dentro do link — sem link/botão dentro.
114
+
115
+ ## Pontos de entrada
116
+
117
+ | Import | Conteúdo |
118
+ | --- | --- |
119
+ | `@trismegisto/spine` | `provideUi`, `SpineConfig`, `ThemeService`, `DensityService`, `SpinePreferencesService`, `provideSpineNews`, textos (`SPINE_MESSAGES`, `provideSpineMessages`) |
120
+ | `@trismegisto/spine/shell` | `APP_ROUTES`, `PUBLIC_ROUTES`, `PRIVATE_ROUTES`, `provideShell`, telas de login e de estado |
121
+ | `@trismegisto/spine/routing` | `ComponentRoute`, `COMPONENT_ROUTES`, `ViewGuard`, `RouteIdInterceptor`, resolução de rota |
122
+ | `@trismegisto/spine/layout` | `LayoutComponent` (`spine-layout`), cabeçalho, menu lateral, onboarding, atalhos, configurações, novidades, documentação |
123
+ | `@trismegisto/spine/modal` | `ModalService` (`open(config)` devolve um `Observable` com o resultado), `ModalContent` |
124
+ | `@trismegisto/spine/side-panel` | `SidePanelService`, `SidePanelContent` |
125
+ | `@trismegisto/spine/notification` | `NotificationService` (`addNotification`) |
126
+ | `@trismegisto/spine/auto-service` | `provideAutoService({ adminApi })`: telas prontas de autosserviço (início, grupos, aplicações, cliente, auditoria), sempre carregadas sob demanda (`AUTO_SERVICE_SCREENS`); as classes das telas não são exportadas. `AutoServiceService` e o tipo `AutoServiceClient` são |
127
+ | `@trismegisto/spine/audit` | A tela de Auditoria (`SpineAuditComponent`, `spine-audit`), a mesma para o painel central (`scope="admin"`) e o auto-serviço (`scope="client"`), + `SpineAuditService` e os tipos/funções puras (`AuditEvent`, `AuditQuery`, `buildAuditQuery`, `auditApiBase`…). **Exporta o componente: importe só de código lazy** |
128
+ | `@trismegisto/spine/graphql` | `provideGraphql({ endpoints })`: um cliente Apollo nomeado por backend |
129
+
130
+ ## Auditoria (`@trismegisto/spine/audit`)
131
+
132
+ Uma tela só para os dois públicos — o dono/membro de projeto (auto-serviço) e o administrador do argos (painel
133
+ central). Lê `audit.events` pelo argos admin-server; só muda o escopo:
134
+
135
+ | `scope` | Endpoints | Apps do filtro |
136
+ | --- | --- | --- |
137
+ | `client` (+ `clientId`) | `{adminApi}/auto-service/:clientId/audit/*` — o servidor recorta aos apps do projeto (`app_id` de fora → 403) | `GET /auto-service/:clientId/apps` |
138
+ | `admin` | `{adminApi}/admin/audit/*` — todos os apps (guard `admin:audit:*`) | `GET /admin/apps` |
139
+
140
+ `adminApi` vem do input `[adminApi]` ou do `SPINE_ADMIN_API` (o `provideAutoService` já fornece).
141
+
142
+ ```ts
143
+ // rota lazy do app (ex.: argos admin/ui)
144
+ component: async () => (await import('./admin-audit-page.component')).AdminAuditPageComponent,
145
+ // …e no template da página: <spine-audit scope="admin" [adminApi]="environment.adminApi" />
146
+ ```
147
+
148
+ - **No auto-serviço:** aba **Auditoria** na página de Aplicações (`import('@trismegisto/spine/audit')` só ao abrir
149
+ a aba) e página própria ligada a `AUTO_SERVICE_AUDIT_TEMPLATE_ROUTER_ID` (`ad100004-…`), que aparece no menu
150
+ "Administração" quando o template `auto-service` do banco tiver esse router. O app não configura nada além do
151
+ `provideAutoService`.
152
+ - **Conteúdo:** período rápido (1h/6h/24h/7d/30d; as datas da faixa de filtros vencem), "Atualizar" + atualização
153
+ automática opcional (30 s), filtros (datas, aplicação — multisseleção —, usuário, operação, método, resultado, só
154
+ ações do usuário, nível, permissão, tipo de ator, status HTTP, trace, ID do usuário; filtros salvos por escopo),
155
+ KPIs (eventos; falhas e negados clicáveis viram filtro de resultado), linha do tempo em barras CSS, **3 rankings
156
+ paginados no servidor** (operações, usuários e, com mais de um app, por aplicação — 5 por página, "x–y de N",
157
+ anterior/próxima; clicar vira filtro), tabela paginada no servidor (cursor; 25/50/100/200 por página = `limit`) e o
158
+ detalhe do evento num `hm-drawer` (identificador + descrição da operação, "Ver cadeia (trace)", "Filtrar a tabela
159
+ por este trace", aviso de `hidden_count`).
160
+ - **Colunas:** Operação mostra só o identificador (`operation_identifier`; a descrição fica na dica da célula e no
161
+ detalhe); Resultado é um `hm-tag` com o texto ("Sucesso"/"Falha"/"Negado", nos 3 idiomas) na cor de status.
162
+ - **Sem piscar:** trocar de página, de ranking ou atualizar mantém as linhas atuais à vista (esmaecidas, com
163
+ `hm-progress` indeterminado por cima e `aria-busy`); esqueleto só na 1ª carga. Respostas fora de ordem (página,
164
+ ranking, consulta ou detalhe já trocados) são descartadas por número de sequência.
165
+ - **Estados:** carregando, vazio (com "Limpar filtros"), erro com "Tentar de novo", janela acima de 31 dias (barrada
166
+ antes de ir ao servidor e `range_too_large`), filtro inválido (`invalid_filter`, com a explicação do servidor) e
167
+ 403 (texto diferente por escopo).
168
+ - **Bundle:** o ponto `audit` exporta o componente de propósito; o `check-lazy` falha se o arquivo do ponto
169
+ principal ou do `auto-service` passar a importá-lo estaticamente.
170
+
171
+ ## Regras que o app precisa saber
172
+
173
+ - **`COMPONENT_ROUTES` é sempre `multi`.** O app contribui pelo `provideShell` e pacotes plugáveis (como o
174
+ `provideAutoService`) pelo deles. Nunca forneça o token sem `multi: true`. Um `id` igual ao de uma tela
175
+ base do shell faz o `provideShell` lançar erro.
176
+ - **Documentação de tela** (`document.load`) é markdown cru importado como texto: configure o loader
177
+ `".md": "text"` no `angular.json` do app. O texto vai no chunk lazy da tela.
178
+ - **Idioma:** os textos do spine seguem `HermesI18nService.setLocale` (o idioma em si se configura com
179
+ `provideHermesI18n` do `@trismegisto/angular`). `provideSpineMessages({ override, catalogs })` só sobrescreve
180
+ textos ou acrescenta idiomas.
181
+ - **Ícones do app** já estão cobertos pelo catálogo inteiro que o `provideUi` registra.
182
+ - `ModalService`/`SidePanelService` abrem um componente que implementa `ModalContent` (`getResult()`,
183
+ `isValid?()`). Para diálogos fora do shell, o `@trismegisto/angular` tem `HermesDialogService`.
184
+
185
+ ## Documentação
186
+
187
+ - A skill de uso para agentes (Claude Code) está no pacote `@acropole/skills`: `npx @acropole/skills`
188
+ (skill `trismegisto`, que cobre o spine). Ela não vai mais dentro deste pacote.
189
+ - Componentes que o shell usa: site de documentação (`docs/website`) e o
190
+ [README do `@trismegisto/angular`](../angular/README.md).
191
+ - Mudanças por versão: [`CHANGELOG.md`](./CHANGELOG.md).
192
+ - Arquitetura: [`docs/architecture`](../../docs/architecture/README.md). Pendências do pacote:
193
+ [`docs/status/open-items.md`](../../docs/status/open-items.md).
194
+
195
+ ## Desenvolvimento do pacote
196
+
197
+ O código fica em `projects/ui/` (um ponto de entrada por pasta). `npm run build` roda o `check-strings`,
198
+ empacota com ng-packagr em `dist/ui/` (o que vai publicado) e copia este README para lá
199
+ (`scripts/copy-readme.mjs`); `npm run check-strings` sozinho confere que
200
+ nenhum texto de interface está fora do catálogo. O build termina com `scripts/check-lazy.mjs`, que falha se uma
201
+ tela carregada por `import()` (as do auto-serviço) acabar colada no arquivo do ponto de entrada, ou se o ponto
202
+ principal/`auto-service` importar `@trismegisto/spine/audit` estaticamente — acontece quando
203
+ ela é exportada no `public-api.ts` (o rollup troca o `import()` por `Promise.resolve()` e a tela vai para o bundle
204
+ inicial do app).
205
+
206
+ O catálogo de API da skill (`spine-api.md`) é gerado pelo `@acropole/skills`, que lê o `projects/ui/` deste pacote
207
+ (rode `npm run sync -- --trismegisto <pasta do trismegisto>` em `packages/acropole`).