@softize/opus 8.6.6
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 +1616 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/bin/cli.mjs +528 -0
- package/bin/lib/check.mjs +307 -0
- package/bin/lib/components.mjs +151 -0
- package/bin/lib/create.mjs +208 -0
- package/bin/lib/db-check-runner.mjs +86 -0
- package/bin/lib/db-migrate-runner.mjs +89 -0
- package/bin/lib/db-scaffold-runner.mjs +84 -0
- package/bin/lib/db.mjs +261 -0
- package/bin/lib/docs-include.mjs +48 -0
- package/bin/lib/gen-dicts.mjs +134 -0
- package/bin/lib/gen-docs.mjs +288 -0
- package/bin/lib/gen-manifest.mjs +102 -0
- package/bin/lib/gen-openapi.mjs +195 -0
- package/bin/lib/gen-runner.mjs +472 -0
- package/bin/lib/gen-stubs.mjs +463 -0
- package/bin/lib/gen.mjs +311 -0
- package/bin/lib/init.mjs +514 -0
- package/bin/lib/introspect.mjs +107 -0
- package/bin/lib/mcp.mjs +85 -0
- package/bin/lib/postinstall.mjs +56 -0
- package/docs/chat-event-protocol.md +85 -0
- package/docs/code-style.md +16 -0
- package/docs/data-layer.md +246 -0
- package/docs/ownership-vs-shadcn-lock.md +102 -0
- package/docs/protocol.md +2053 -0
- package/docs/releasing.md +110 -0
- package/docs/shellnav.md +131 -0
- package/package.json +338 -0
- package/registry/hooks/hooks.json +26 -0
- package/registry/hooks/link-memory-on-start.mjs +46 -0
- package/registry/hooks/opus-check-on-stop.mjs +114 -0
- package/registry/skills/create-action/SKILL.md +49 -0
- package/registry/skills/create-action/scaffold.mjs +122 -0
- package/registry/templates/app/_gitignore +3 -0
- package/registry/templates/app/_npmrc +1 -0
- package/registry/templates/app/_opus/_gitignore +5 -0
- package/registry/templates/app/_prettierrc.json +6 -0
- package/registry/templates/app/index.html +13 -0
- package/registry/templates/app/opus.config.ts +16 -0
- package/registry/templates/app/package.json +43 -0
- package/registry/templates/app/pnpm-workspace.yaml +11 -0
- package/registry/templates/app/public/favicon.svg +4 -0
- package/registry/templates/app/src/App.tsx +37 -0
- package/registry/templates/app/src/domains/tasks/actions/list.test.ts +34 -0
- package/registry/templates/app/src/domains/tasks/actions/list.ts +33 -0
- package/registry/templates/app/src/domains/tasks/index.ts +13 -0
- package/registry/templates/app/src/index.css +18 -0
- package/registry/templates/app/src/main.tsx +25 -0
- package/registry/templates/app/tsconfig.json +20 -0
- package/registry/templates/app/vite.config.ts +46 -0
- package/registry/templates/monorepo/_gitignore +3 -0
- package/registry/templates/monorepo/_npmrc +1 -0
- package/registry/templates/monorepo/package.json +9 -0
- package/registry/templates/monorepo/pnpm-workspace.yaml +14 -0
- package/src/ai/ask.ts +64 -0
- package/src/ai/drivers/anthropic.ts +309 -0
- package/src/ai/index.ts +17 -0
- package/src/audit/drivers/console.ts +117 -0
- package/src/audit/drivers/pg.ts +172 -0
- package/src/audit/index.ts +51 -0
- package/src/auth/drivers/better-auth.ts +103 -0
- package/src/auth/drivers/jwt.ts +188 -0
- package/src/auth/index.ts +9 -0
- package/src/client/drivers/fetch.ts +202 -0
- package/src/client/index.ts +22 -0
- package/src/core/actions.ts +110 -0
- package/src/core/audit.ts +239 -0
- package/src/core/contracts.ts +137 -0
- package/src/core/domain.ts +310 -0
- package/src/core/errors.ts +181 -0
- package/src/core/index.ts +174 -0
- package/src/core/logical-type.ts +31 -0
- package/src/core/reactions.ts +81 -0
- package/src/core/runtime.ts +1167 -0
- package/src/core/schedules.ts +41 -0
- package/src/core/types.ts +1356 -0
- package/src/data/drivers/kysely.ts +389 -0
- package/src/data/index.ts +10 -0
- package/src/data/readonly-pool.ts +160 -0
- package/src/dsl/eval.ts +136 -0
- package/src/dsl/index.ts +29 -0
- package/src/dsl/kysely.ts +230 -0
- package/src/dsl/loads.ts +123 -0
- package/src/dsl/parser.ts +423 -0
- package/src/dsl/types.ts +113 -0
- package/src/events/drivers/mitt.ts +70 -0
- package/src/events/index.ts +9 -0
- package/src/log/drivers/pino.ts +57 -0
- package/src/log/index.ts +9 -0
- package/src/mcp/index.ts +62 -0
- package/src/queue/drivers/bullmq.ts +190 -0
- package/src/queue/index.ts +9 -0
- package/src/scheduler/drivers/node-cron.ts +93 -0
- package/src/scheduler/every.ts +45 -0
- package/src/scheduler/index.ts +9 -0
- package/src/schema/drivers/zod.ts +765 -0
- package/src/schema/entity.ts +439 -0
- package/src/schema/format/locale.ts +144 -0
- package/src/schema/index.ts +65 -0
- package/src/schema/openapi.ts +302 -0
- package/src/schema/scaffold.ts +160 -0
- package/src/server/drivers/fastify.ts +224 -0
- package/src/server/drivers/node.ts +386 -0
- package/src/server/index.ts +142 -0
- package/src/storage/drivers/fs.ts +90 -0
- package/src/storage/drivers/s3.ts +117 -0
- package/src/storage/index.ts +27 -0
- package/src/testing/fake.ts +298 -0
- package/src/testing/index.ts +324 -0
- package/src/ui/components/patterns/action-form-card.tsx +48 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +93 -0
- package/src/ui/components/patterns/app-shell.tsx +227 -0
- package/src/ui/components/patterns/confirm.tsx +226 -0
- package/src/ui/components/patterns/data-state.tsx +75 -0
- package/src/ui/components/patterns/form-dialog.tsx +64 -0
- package/src/ui/components/patterns/form.tsx +584 -0
- package/src/ui/components/patterns/list.tsx +1488 -0
- package/src/ui/components/patterns/page.tsx +46 -0
- package/src/ui/components/patterns/section-shell.tsx +246 -0
- package/src/ui/components/patterns/shell-nav.tsx +150 -0
- package/src/ui/components/patterns/sidebar.tsx +89 -0
- package/src/ui/components/patterns/split.tsx +93 -0
- package/src/ui/components/patterns/trigger.tsx +196 -0
- package/src/ui/components/patterns/view.tsx +84 -0
- package/src/ui/components/primitives/accordion.tsx +64 -0
- package/src/ui/components/primitives/alert-dialog.tsx +190 -0
- package/src/ui/components/primitives/alert.tsx +116 -0
- package/src/ui/components/primitives/aspect-ratio.tsx +9 -0
- package/src/ui/components/primitives/avatar.tsx +107 -0
- package/src/ui/components/primitives/badge.tsx +37 -0
- package/src/ui/components/primitives/breadcrumb.tsx +109 -0
- package/src/ui/components/primitives/button-group.tsx +83 -0
- package/src/ui/components/primitives/button.tsx +102 -0
- package/src/ui/components/primitives/calendar.tsx +218 -0
- package/src/ui/components/primitives/card.tsx +56 -0
- package/src/ui/components/primitives/carousel.tsx +239 -0
- package/src/ui/components/primitives/chat.tsx +407 -0
- package/src/ui/components/primitives/checkbox.tsx +30 -0
- package/src/ui/components/primitives/collapsible.tsx +31 -0
- package/src/ui/components/primitives/command.tsx +182 -0
- package/src/ui/components/primitives/composer.tsx +121 -0
- package/src/ui/components/primitives/copyable.tsx +50 -0
- package/src/ui/components/primitives/dialog.tsx +147 -0
- package/src/ui/components/primitives/drawer.tsx +141 -0
- package/src/ui/components/primitives/empty.tsx +104 -0
- package/src/ui/components/primitives/field.tsx +246 -0
- package/src/ui/components/primitives/icon-picker.tsx +180 -0
- package/src/ui/components/primitives/input-group.tsx +168 -0
- package/src/ui/components/primitives/input-otp.tsx +75 -0
- package/src/ui/components/primitives/input.tsx +72 -0
- package/src/ui/components/primitives/item.tsx +193 -0
- package/src/ui/components/primitives/kbd.tsx +28 -0
- package/src/ui/components/primitives/label.tsx +22 -0
- package/src/ui/components/primitives/markdown.tsx +35 -0
- package/src/ui/components/primitives/menu.tsx +255 -0
- package/src/ui/components/primitives/pagination.tsx +127 -0
- package/src/ui/components/primitives/popover.tsx +87 -0
- package/src/ui/components/primitives/progress.tsx +29 -0
- package/src/ui/components/primitives/radio-group.tsx +43 -0
- package/src/ui/components/primitives/resizable.tsx +51 -0
- package/src/ui/components/primitives/scroll-area.tsx +56 -0
- package/src/ui/components/primitives/select.tsx +479 -0
- package/src/ui/components/primitives/separator.tsx +26 -0
- package/src/ui/components/primitives/skeleton.tsx +13 -0
- package/src/ui/components/primitives/slider.tsx +61 -0
- package/src/ui/components/primitives/sonner.tsx +46 -0
- package/src/ui/components/primitives/spinner.tsx +29 -0
- package/src/ui/components/primitives/switch.tsx +33 -0
- package/src/ui/components/primitives/table.tsx +114 -0
- package/src/ui/components/primitives/tabs.tsx +104 -0
- package/src/ui/components/primitives/textarea.tsx +18 -0
- package/src/ui/components/primitives/toggle-group.tsx +81 -0
- package/src/ui/components/primitives/toggle.tsx +45 -0
- package/src/ui/components/primitives/tooltip.tsx +55 -0
- package/src/ui/components/primitives/truncate.tsx +49 -0
- package/src/ui/docs/DocBrowser.tsx +90 -0
- package/src/ui/docs/changelog.tsx +80 -0
- package/src/ui/docs/content/accordion.md +86 -0
- package/src/ui/docs/content/action-form-card.md +24 -0
- package/src/ui/docs/content/action-form-dialog.md +30 -0
- package/src/ui/docs/content/action-form.md +125 -0
- package/src/ui/docs/content/action-list-dialog.md +68 -0
- package/src/ui/docs/content/action-list.md +194 -0
- package/src/ui/docs/content/action-trigger.md +72 -0
- package/src/ui/docs/content/action-view.md +47 -0
- package/src/ui/docs/content/actions.md +138 -0
- package/src/ui/docs/content/ai.md +112 -0
- package/src/ui/docs/content/alert-dialog.md +73 -0
- package/src/ui/docs/content/alert.md +69 -0
- package/src/ui/docs/content/app-shell.md +155 -0
- package/src/ui/docs/content/aspect-ratio.md +66 -0
- package/src/ui/docs/content/audit.md +84 -0
- package/src/ui/docs/content/auth.md +70 -0
- package/src/ui/docs/content/avatar.md +94 -0
- package/src/ui/docs/content/badge.md +48 -0
- package/src/ui/docs/content/breadcrumb.md +87 -0
- package/src/ui/docs/content/button-group.md +71 -0
- package/src/ui/docs/content/button.md +60 -0
- package/src/ui/docs/content/calendar.md +62 -0
- package/src/ui/docs/content/card.md +49 -0
- package/src/ui/docs/content/carousel.md +85 -0
- package/src/ui/docs/content/chat.md +69 -0
- package/src/ui/docs/content/checkbox.md +75 -0
- package/src/ui/docs/content/cli.md +58 -0
- package/src/ui/docs/content/collapsible.md +64 -0
- package/src/ui/docs/content/command.md +56 -0
- package/src/ui/docs/content/composer.md +50 -0
- package/src/ui/docs/content/confirm.md +120 -0
- package/src/ui/docs/content/copyable.md +30 -0
- package/src/ui/docs/content/customization.md +110 -0
- package/src/ui/docs/content/cycle.md +34 -0
- package/src/ui/docs/content/data-state.md +47 -0
- package/src/ui/docs/content/data.md +99 -0
- package/src/ui/docs/content/dialog.md +60 -0
- package/src/ui/docs/content/drawer.md +55 -0
- package/src/ui/docs/content/empty.md +66 -0
- package/src/ui/docs/content/events.md +61 -0
- package/src/ui/docs/content/field.md +58 -0
- package/src/ui/docs/content/getting-started.md +109 -0
- package/src/ui/docs/content/icon-picker.md +51 -0
- package/src/ui/docs/content/input-group.md +78 -0
- package/src/ui/docs/content/input-otp.md +72 -0
- package/src/ui/docs/content/input.md +78 -0
- package/src/ui/docs/content/item.md +84 -0
- package/src/ui/docs/content/kbd.md +62 -0
- package/src/ui/docs/content/label.md +32 -0
- package/src/ui/docs/content/log.md +55 -0
- package/src/ui/docs/content/markdown.md +41 -0
- package/src/ui/docs/content/mcp.md +44 -0
- package/src/ui/docs/content/menu.md +114 -0
- package/src/ui/docs/content/microcopy.md +83 -0
- package/src/ui/docs/content/page.md +34 -0
- package/src/ui/docs/content/pagination.md +99 -0
- package/src/ui/docs/content/popover.md +49 -0
- package/src/ui/docs/content/progress.md +69 -0
- package/src/ui/docs/content/queue.md +62 -0
- package/src/ui/docs/content/radio-group.md +77 -0
- package/src/ui/docs/content/resizable.md +86 -0
- package/src/ui/docs/content/router.md +56 -0
- package/src/ui/docs/content/runtime.md +77 -0
- package/src/ui/docs/content/scheduler.md +66 -0
- package/src/ui/docs/content/scroll-area.md +89 -0
- package/src/ui/docs/content/section-shell.md +121 -0
- package/src/ui/docs/content/select.md +342 -0
- package/src/ui/docs/content/separator.md +33 -0
- package/src/ui/docs/content/sidebar.md +38 -0
- package/src/ui/docs/content/skeleton.md +34 -0
- package/src/ui/docs/content/slider.md +64 -0
- package/src/ui/docs/content/spinner.md +37 -0
- package/src/ui/docs/content/split.md +33 -0
- package/src/ui/docs/content/storage.md +69 -0
- package/src/ui/docs/content/switch.md +69 -0
- package/src/ui/docs/content/table.md +102 -0
- package/src/ui/docs/content/tabs.md +94 -0
- package/src/ui/docs/content/testing.md +89 -0
- package/src/ui/docs/content/textarea.md +30 -0
- package/src/ui/docs/content/toast.md +67 -0
- package/src/ui/docs/content/toggle-group.md +81 -0
- package/src/ui/docs/content/toggle.md +72 -0
- package/src/ui/docs/content/tokens.md +171 -0
- package/src/ui/docs/content/tooltip.md +50 -0
- package/src/ui/docs/content/truncate.md +37 -0
- package/src/ui/docs/content/ui.md +40 -0
- package/src/ui/docs/content/upgrading.md +48 -0
- package/src/ui/docs/doc-client.tsx +214 -0
- package/src/ui/docs/doc.tsx +301 -0
- package/src/ui/docs/folder.tsx +149 -0
- package/src/ui/docs/index.ts +21 -0
- package/src/ui/docs/markdown.tsx +130 -0
- package/src/ui/docs/md-raw.d.ts +4 -0
- package/src/ui/docs/plugin.ts +104 -0
- package/src/ui/docs/registry.tsx +424 -0
- package/src/ui/docs/standalone.tsx +107 -0
- package/src/ui/drivers/react.tsx +627 -0
- package/src/ui/index.ts +92 -0
- package/src/ui/lib/cn.ts +10 -0
- package/src/ui/lib/zod-pt-br.ts +38 -0
- package/src/ui/meta.ts +412 -0
- package/src/ui/react.tsx +235 -0
- package/src/ui/router.ts +96 -0
- package/src/ui/theme.css +234 -0
- package/src/vite/design.ts +652 -0
- package/src/vite/index.ts +8 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Publicar o pacote
|
|
3
|
+
order: 6
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Publicar o @softize/opus
|
|
7
|
+
|
|
8
|
+
O Opus é publicado no **registry compartilhado da Softize** (`registry.softize.com.br`),
|
|
9
|
+
**não** no npm público. Os clientes consomem de lá.
|
|
10
|
+
|
|
11
|
+
> O `publishConfig` do `package.json` já aponta pra lá — `pnpm publish` "só funciona",
|
|
12
|
+
> sem `--registry`. Não precisa decorar a URL.
|
|
13
|
+
|
|
14
|
+
## Release pela estação (o caminho normal)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm release # patch bump + publica no registry.softize.com.br
|
|
18
|
+
pnpm release minor # minor
|
|
19
|
+
pnpm release major # major
|
|
20
|
+
pnpm release 2.9.0 # versão explícita
|
|
21
|
+
pnpm release none # publica sem bump
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Auth: o token do registry no `~/.npmrc` global (`//registry.softize.com.br/:_authToken=…`),
|
|
25
|
+
NÃO commitado.
|
|
26
|
+
|
|
27
|
+
## Não existe caminho pela CI (29/jul)
|
|
28
|
+
|
|
29
|
+
A camada de GitHub Actions foi **removida** deste repo — `.github/` não existe mais. Saíram
|
|
30
|
+
o `release.yml` (publicava por tag `v*`), o `deploy.yml` (doc, já reserva) e o `check.yml`
|
|
31
|
+
(typecheck+test em push/PR). É a mesma decisão do monorepo (ADR 0008 do softize): um
|
|
32
|
+
caminho só, na estação, com os gates junto. Não há gatilho de reserva.
|
|
33
|
+
|
|
34
|
+
O secret **`OPUS_REGISTRY_TOKEN`** ficou órfão — nada mais o lê. Apague no GitHub. O que
|
|
35
|
+
autentica hoje é o token do registry no seu `~/.npmrc` global.
|
|
36
|
+
|
|
37
|
+
**O que o `release.sh` absorveu**, porque sem CI ficaria sem dono:
|
|
38
|
+
|
|
39
|
+
- **Procedência** — as três guardas que só o `deploy-docs.sh` tinha: precisa estar na
|
|
40
|
+
`main`, com árvore limpa (`--porcelain`, que pega não-rastreado) e igual a `origin/main`.
|
|
41
|
+
Rodam ANTES do bump, que suja a árvore de propósito. Antes isso vinha de graça: a release
|
|
42
|
+
nascia de um checkout limpo da tag, e a árvore do dev nunca entrava no tarball.
|
|
43
|
+
- **Bump na main, automático** — a guarda `tag=versão` do CI existia pra impedir registry e
|
|
44
|
+
main divergindo em silêncio. Como aqui o bump acontece DEPOIS (o script versiona e
|
|
45
|
+
publica), a proteção equivalente é o script commitar e empurrar o bump sozinho ao fim. Se
|
|
46
|
+
o push falhar depois de o publish ter ido, ele grita e sai 1 — a versão existe pro cliente
|
|
47
|
+
e não existe no repo, e isso não pode passar como aviso no meio do log.
|
|
48
|
+
- **Smoke do esqueleto** — já tinha descido pro script antes (ver abaixo).
|
|
49
|
+
|
|
50
|
+
`--local` (Verdaccio) não passa pelas guardas de procedência: é sandbox, e exigir main limpa
|
|
51
|
+
pra testar publicação seria a guarda atrapalhando quem está experimentando.
|
|
52
|
+
|
|
53
|
+
**Gate de qualidade**: antes de bumpar/publicar roda `pnpm typecheck`
|
|
54
|
+
+ `pnpm test` e **aborta a release se qualquer um falhar**. Como o Opus **ship source** (`.ts`,
|
|
55
|
+
sem build), essa é a última barreira antes do tarball — sem ela, um `tsc` vermelho vaza pro
|
|
56
|
+
cliente. Emergência (evite): `pnpm release --skip-checks`.
|
|
57
|
+
|
|
58
|
+
**Smoke do esqueleto**: depois do bump e antes do publish, o `release.sh` gera um app com
|
|
59
|
+
`opus create`, instala o **tarball exato** que vai ser publicado e roda os gates dele
|
|
60
|
+
(typecheck · test · `opus check` · manifest · build). É o que pega o que typecheck+test não
|
|
61
|
+
alcançam — `files` mal recortado, export que só resolve por caminho relativo, template
|
|
62
|
+
pinado numa versão que ainda não existe no registry. Ele vivia só no `release.yml`; como as
|
|
63
|
+
últimas releases saíram pela estação (sem tag), passou tempo sem rodar, e foi assim que o
|
|
64
|
+
template chegou a quebrar o `tsc` de um app recém-criado. `--skip-checks` pula junto.
|
|
65
|
+
|
|
66
|
+
O script bumpa, publica **e leva o bump pra `origin/main`** — não sobra passo manual. Em
|
|
67
|
+
`--local` ele não commita nada (Verdaccio é sandbox), e com `pnpm release none` não há bump
|
|
68
|
+
pra commitar.
|
|
69
|
+
|
|
70
|
+
## Verificar
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm view @softize/opus version --registry https://registry.softize.com.br/
|
|
74
|
+
# ou
|
|
75
|
+
curl -s https://registry.softize.com.br/@softize%2fopus | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>console.log(JSON.parse(d)['dist-tags'].latest))"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Testar localmente (sem tocar no compartilhado)
|
|
79
|
+
|
|
80
|
+
Para validar uma mudança de API em consumidores locais, publique uma **prerelease** no
|
|
81
|
+
Verdaccio e instale exatamente essa versão. Isso reproduz o pacote como será consumido —
|
|
82
|
+
sem `link:`/`file:`, que podem mascarar exports e peers.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# terminal 1 — uma vez por máquina/sessão
|
|
86
|
+
pnpm registry:up # Verdaccio em 127.0.0.1:6873
|
|
87
|
+
|
|
88
|
+
# terminal 2 — no Opus
|
|
89
|
+
pnpm version 8.7.0-rc.0 --no-git-tag-version # escolha uma versão ainda não publicada
|
|
90
|
+
# adicione a seção "## 8.7.0-rc.0" ao CHANGELOG.md
|
|
91
|
+
pnpm release:local none # gates + publish SOMENTE local
|
|
92
|
+
|
|
93
|
+
# em cada consumidor
|
|
94
|
+
pnpm add @softize/opus@8.7.0-rc.0 --registry http://127.0.0.1:6873/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Valide o app normalmente. Ao encerrar a sessão, restaure o intervalo de versão do
|
|
98
|
+
consumidor para o registry compartilhado e rode `pnpm install`; a prerelease local nunca
|
|
99
|
+
é enviada para `registry.softize.com.br`. Para publicar outra tentativa, incremente o
|
|
100
|
+
sucesso (`8.6.0-rc.1`, por exemplo) e repita o mesmo fluxo.
|
|
101
|
+
|
|
102
|
+
## Auth
|
|
103
|
+
|
|
104
|
+
O publish no compartilhado exige o token no **`~/.npmrc` global** do dev:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
//registry.softize.com.br/:_authToken=<token>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Não vai no repo. Leitura (install) é aberta — não precisa de token.
|
package/docs/shellnav.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Proposta: `ShellNav` — o menu como primitivo pivotável
|
|
2
|
+
|
|
3
|
+
> **Status: EM DISCUSSÃO.** Desenhado com o João (2026-07-22), a partir do trabalho na
|
|
4
|
+
> cabine do Maestro (a nav do projeto virou `SectionShell`; a sidebar ganhou Início +
|
|
5
|
+
> Configurações). Pendente de aprovação e de uma versão do Opus. Refina o
|
|
6
|
+
> [`ownership-vs-shadcn-lock`](ownership-vs-shadcn-lock.md): o item de menu é o próximo
|
|
7
|
+
> primitivo a sair do "cada app copia ad-hoc".
|
|
8
|
+
|
|
9
|
+
## O problema
|
|
10
|
+
|
|
11
|
+
O `AppShell` entrega a **moldura** da sidebar (o slot `sidebarNav`) e o `SectionShell`
|
|
12
|
+
entrega a **nav de seção** (nav + painel, dentro do conteúdo). Mas o **item de menu** — a
|
|
13
|
+
linha com ícone + label + estado ativo + badge — não é primitivo de ninguém: cada app
|
|
14
|
+
escreve o `<button className="…">` na mão. Resultado, medido (não suposto):
|
|
15
|
+
|
|
16
|
+
| Menu | Onde | Como é feito hoje |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Aplicação (sidebar) | `AppShell.sidebarNav` | `<button>` à mão — sem primitivo |
|
|
19
|
+
| Configurações | dentro do conteúdo | `SectionShell` (primitivo) ✓ |
|
|
20
|
+
| Relatórios | dentro do conteúdo | `<aside>`/`<nav>` à mão — **não usa o SectionShell**, mesmo sendo a mesma forma |
|
|
21
|
+
|
|
22
|
+
E isso se repete em **três produtos** (`softize/apps/maestro`, `softize/apps/main/web`,
|
|
23
|
+
`empresa-x/apps/main`), cada um com a própria cópia do item — e, dentro de cada um, o
|
|
24
|
+
markup ainda se repete por estado (ativo/inativo/recolhido) e nível (pai/filho).
|
|
25
|
+
|
|
26
|
+
Dois fatos que calibram a urgência:
|
|
27
|
+
|
|
28
|
+
- **Não é drift visível — é duplicação + risco.** Diff token a token: mesma versão do Opus
|
|
29
|
+
(2.37), mesmo `--radius` (0.625rem), classes de forma **byte-a-byte iguais**
|
|
30
|
+
(`rounded-md px-2.5 py-1.5 gap-2.5`). Só continuam iguais porque um humano copia; nada
|
|
31
|
+
cobra. A "sensação de divergência" (item mais retangular numa app que noutra) vem de
|
|
32
|
+
comparar **componentes diferentes** (nav de app × nav de seção × switcher), não de drift
|
|
33
|
+
do mesmo componente.
|
|
34
|
+
- **Já há uma inconsistência viva:** o menu de Relatórios do GB é uma nav-dentro-do-conteúdo
|
|
35
|
+
— a MESMA forma do Configurações — e mesmo assim hand-rola em vez de usar o `SectionShell`.
|
|
36
|
+
|
|
37
|
+
## A proposta
|
|
38
|
+
|
|
39
|
+
Um primitivo só: **`ShellNav`** — **pivotável e controlado** (presentacional, como o
|
|
40
|
+
`SectionShell` já é). O app passa **dados**, não markup, e o mesmo componente serve os dois
|
|
41
|
+
lares sem flag de "modo app" vs "modo seção":
|
|
42
|
+
|
|
43
|
+
- Na **sidebar do AppShell** (`sidebarNav={<ShellNav …/>}`): lê o estado de recolhido do
|
|
44
|
+
contexto `useAppShell` e vira ícone-só sozinho.
|
|
45
|
+
- **Dentro do conteúdo** (o que o `SectionShell` faz): sem esse contexto, renderiza
|
|
46
|
+
expandido. O `SectionShell` **passa a compor** `ShellNav` (a nav) + o painel — um nav,
|
|
47
|
+
dois lares.
|
|
48
|
+
|
|
49
|
+
Isto é o "tanto faz onde, mesmo comportamento": o componente **se adapta ao contexto** via
|
|
50
|
+
`useAppShell`, sem o consumidor configurar nada.
|
|
51
|
+
|
|
52
|
+
### Heading com espaço pra botão
|
|
53
|
+
|
|
54
|
+
Slot `heading` — título + ação opcional. É o "+" de novo relatório, o título da seção, a
|
|
55
|
+
marca na sidebar. Trivial e resolve o gesto que hoje mora à mão em cada nav.
|
|
56
|
+
|
|
57
|
+
### Árvore embutida; DnD composto (a régua)
|
|
58
|
+
|
|
59
|
+
- **Aninhamento/árvore → dentro do `ShellNav`.** Não é feature nova: o accordion da sidebar
|
|
60
|
+
(Vendas → Leads/Propostas, no GB) já é uma árvore de um nível. Barato, já necessário.
|
|
61
|
+
- **Drag-drop de reordenar → COMPOSTO por fora**, estilo `dnd-kit`: o `ShellNav` expõe a
|
|
62
|
+
costura (um wrapper de item + um slot pro indicador de drop); um companheiro
|
|
63
|
+
(`useNavReorder`) pluga o arrasto só onde se opta. O peso — estado de drag, indicadores,
|
|
64
|
+
toque e principalmente a **a11y** (nav é *landmark*; reorder é *widget de manipulação* —
|
|
65
|
+
identidades diferentes) — vive fora do primitivo.
|
|
66
|
+
|
|
67
|
+
**O critério (viaja pra próximas decisões de primitivo): embute o que a maioria
|
|
68
|
+
compartilha; compõe o que um só precisa.** Reordenar é feature de um consumidor (só o
|
|
69
|
+
Relatórios); embuti-la faria os muitos pagarem a complexidade pelo um.
|
|
70
|
+
|
|
71
|
+
### GB é a aparência de referência
|
|
72
|
+
|
|
73
|
+
Das três, a implementação do GB é a mais madura (tem rail/colapso, accordion, estados
|
|
74
|
+
ativos, âncora inferior de Configurações). **O `ShellNav` codifica o look do GB como
|
|
75
|
+
default** — nada regride: o GB migra pro primitivo e renderiza igual; a cabine (já alinhada
|
|
76
|
+
às classes do GB) passa a ser *literalmente* o mesmo componente, e a "sensação de
|
|
77
|
+
retangular" some. A **identidade por app** continua nos **tokens** (`--radius`, cores — o
|
|
78
|
+
Opus já permite sobrescrever no `theme.css` do app), não num fork do componente: a forma é
|
|
79
|
+
compartilhada; a pele é temável.
|
|
80
|
+
|
|
81
|
+
## API (esboço)
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
interface ShellNavItem {
|
|
85
|
+
id: string
|
|
86
|
+
label: string
|
|
87
|
+
icon?: ReactNode
|
|
88
|
+
badge?: ReactNode
|
|
89
|
+
disabled?: boolean
|
|
90
|
+
children?: ShellNavItem[] // accordion (app) / pasta (relatórios)
|
|
91
|
+
}
|
|
92
|
+
interface ShellNavGroup { label?: string; items: ShellNavItem[] }
|
|
93
|
+
|
|
94
|
+
interface ShellNavProps {
|
|
95
|
+
groups: ShellNavGroup[]
|
|
96
|
+
activeId?: string
|
|
97
|
+
onSelect: (id: string) => void
|
|
98
|
+
heading?: ReactNode // título + espaço pra botão (o "+" do Relatórios)
|
|
99
|
+
footer?: ReactNode // âncora inferior (Configurações, no app)
|
|
100
|
+
collapsed?: boolean // override; default lê do useAppShell quando presente
|
|
101
|
+
navLabel?: string
|
|
102
|
+
reorder?: NavReorderSeam // opt-in; sem isto, ZERO DnD (o dnd-kit/useNavReorder pluga aqui)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Conveniência do heading (padroniza título + ação):
|
|
106
|
+
<ShellNavHeading title="Relatórios" action={<Button size="icon" icon={Plus} …/>} />
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
O `SectionShell` reescreve por dentro pra `<ShellNav/>` + painel; sua API pública não muda
|
|
110
|
+
(consumidores existentes seguem).
|
|
111
|
+
|
|
112
|
+
## Hoje × proposto
|
|
113
|
+
|
|
114
|
+
| Menu | Hoje | Proposto |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| App (sidebar) | `<button>` à mão, N cópias por estado | `AppShell sidebarNav={<ShellNav groups footer=Configurações/>}` — colapso via contexto |
|
|
117
|
+
| Configurações | `SectionShell` (nav+painel à mão por dentro) | `SectionShell` compõe `ShellNav` — sem mudança pro consumidor |
|
|
118
|
+
| Relatórios | `<aside>` + tree + DnD, tudo à mão | `<ShellNav heading={título+"+"} …/>` + `useNavReorder` ao lado |
|
|
119
|
+
|
|
120
|
+
## Consequências / plano
|
|
121
|
+
|
|
122
|
+
- **Escopo:** sessão dedicada no Opus (não é ajuste de app). Ciclo: desenhar a API →
|
|
123
|
+
publicar versão do Opus → migrar os consumidores (cada `<button>` à mão vira `groups={…}`).
|
|
124
|
+
- **Custo:** baixo em código, alto em coordenação (bump + migração dos 3 produtos + gates
|
|
125
|
+
em cada). O `SectionShell` é o precedente vivo — foi o mesmo movimento, um nível abaixo.
|
|
126
|
+
- **Ordem sugerida:** (1) `ShellNav` + `ShellNavHeading` no Opus com o look do GB como
|
|
127
|
+
default; (2) `SectionShell` passa a compor; (3) migrar a cabine do Maestro (primeiro
|
|
128
|
+
cliente, já alinhada); (4) migrar o back-office; (5) migrar o Relatórios do GB pra
|
|
129
|
+
`ShellNav` + `useNavReorder` (fecha a inconsistência viva).
|
|
130
|
+
- **Não-objetivo:** o `ShellNav` não vira dono de DnD, tree-editor ou roteamento — segue
|
|
131
|
+
presentacional/controlado; o app é dono do roteamento e do estado.
|
package/package.json
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@softize/opus",
|
|
3
|
+
"version": "8.6.6",
|
|
4
|
+
"description": "End-to-end action protocol for TypeScript. Single package with subpath exports (core + adapters).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"private": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/core/index.ts",
|
|
11
|
+
"default": "./src/core/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
"./check": {
|
|
15
|
+
"default": "./bin/lib/check.mjs"
|
|
16
|
+
},
|
|
17
|
+
"./introspect": {
|
|
18
|
+
"default": "./bin/lib/introspect.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./init": {
|
|
21
|
+
"default": "./bin/lib/init.mjs"
|
|
22
|
+
},
|
|
23
|
+
"./docs-include": "./bin/lib/docs-include.mjs",
|
|
24
|
+
"./core": {
|
|
25
|
+
"types": "./src/core/index.ts",
|
|
26
|
+
"default": "./src/core/index.ts"
|
|
27
|
+
},
|
|
28
|
+
"./audit": {
|
|
29
|
+
"types": "./src/audit/index.ts",
|
|
30
|
+
"default": "./src/audit/index.ts"
|
|
31
|
+
},
|
|
32
|
+
"./audit/console": {
|
|
33
|
+
"types": "./src/audit/drivers/console.ts",
|
|
34
|
+
"default": "./src/audit/drivers/console.ts"
|
|
35
|
+
},
|
|
36
|
+
"./audit/pg": {
|
|
37
|
+
"types": "./src/audit/drivers/pg.ts",
|
|
38
|
+
"default": "./src/audit/drivers/pg.ts"
|
|
39
|
+
},
|
|
40
|
+
"./auth": {
|
|
41
|
+
"types": "./src/auth/index.ts",
|
|
42
|
+
"default": "./src/auth/index.ts"
|
|
43
|
+
},
|
|
44
|
+
"./auth/jwt": {
|
|
45
|
+
"types": "./src/auth/drivers/jwt.ts",
|
|
46
|
+
"default": "./src/auth/drivers/jwt.ts"
|
|
47
|
+
},
|
|
48
|
+
"./auth/better-auth": {
|
|
49
|
+
"types": "./src/auth/drivers/better-auth.ts",
|
|
50
|
+
"default": "./src/auth/drivers/better-auth.ts"
|
|
51
|
+
},
|
|
52
|
+
"./client": {
|
|
53
|
+
"types": "./src/client/index.ts",
|
|
54
|
+
"default": "./src/client/index.ts"
|
|
55
|
+
},
|
|
56
|
+
"./client/fetch": {
|
|
57
|
+
"types": "./src/client/drivers/fetch.ts",
|
|
58
|
+
"default": "./src/client/drivers/fetch.ts"
|
|
59
|
+
},
|
|
60
|
+
"./data": {
|
|
61
|
+
"types": "./src/data/index.ts",
|
|
62
|
+
"default": "./src/data/index.ts"
|
|
63
|
+
},
|
|
64
|
+
"./data/kysely": {
|
|
65
|
+
"types": "./src/data/drivers/kysely.ts",
|
|
66
|
+
"default": "./src/data/drivers/kysely.ts"
|
|
67
|
+
},
|
|
68
|
+
"./data/readonly-pool": {
|
|
69
|
+
"types": "./src/data/readonly-pool.ts",
|
|
70
|
+
"default": "./src/data/readonly-pool.ts"
|
|
71
|
+
},
|
|
72
|
+
"./dsl": {
|
|
73
|
+
"types": "./src/dsl/index.ts",
|
|
74
|
+
"default": "./src/dsl/index.ts"
|
|
75
|
+
},
|
|
76
|
+
"./events": {
|
|
77
|
+
"types": "./src/events/index.ts",
|
|
78
|
+
"default": "./src/events/index.ts"
|
|
79
|
+
},
|
|
80
|
+
"./events/mitt": {
|
|
81
|
+
"types": "./src/events/drivers/mitt.ts",
|
|
82
|
+
"default": "./src/events/drivers/mitt.ts"
|
|
83
|
+
},
|
|
84
|
+
"./log": {
|
|
85
|
+
"types": "./src/log/index.ts",
|
|
86
|
+
"default": "./src/log/index.ts"
|
|
87
|
+
},
|
|
88
|
+
"./log/pino": {
|
|
89
|
+
"types": "./src/log/drivers/pino.ts",
|
|
90
|
+
"default": "./src/log/drivers/pino.ts"
|
|
91
|
+
},
|
|
92
|
+
"./queue": {
|
|
93
|
+
"types": "./src/queue/index.ts",
|
|
94
|
+
"default": "./src/queue/index.ts"
|
|
95
|
+
},
|
|
96
|
+
"./queue/bullmq": {
|
|
97
|
+
"types": "./src/queue/drivers/bullmq.ts",
|
|
98
|
+
"default": "./src/queue/drivers/bullmq.ts"
|
|
99
|
+
},
|
|
100
|
+
"./scheduler": {
|
|
101
|
+
"types": "./src/scheduler/index.ts",
|
|
102
|
+
"default": "./src/scheduler/index.ts"
|
|
103
|
+
},
|
|
104
|
+
"./scheduler/node-cron": {
|
|
105
|
+
"types": "./src/scheduler/drivers/node-cron.ts",
|
|
106
|
+
"default": "./src/scheduler/drivers/node-cron.ts"
|
|
107
|
+
},
|
|
108
|
+
"./storage": "./src/storage/index.ts",
|
|
109
|
+
"./storage/fs": "./src/storage/drivers/fs.ts",
|
|
110
|
+
"./storage/s3": "./src/storage/drivers/s3.ts",
|
|
111
|
+
"./ai": "./src/ai/index.ts",
|
|
112
|
+
"./ai/anthropic": "./src/ai/drivers/anthropic.ts",
|
|
113
|
+
"./mcp": "./src/mcp/index.ts",
|
|
114
|
+
"./testing": {
|
|
115
|
+
"types": "./src/testing/index.ts",
|
|
116
|
+
"default": "./src/testing/index.ts"
|
|
117
|
+
},
|
|
118
|
+
"./schema": {
|
|
119
|
+
"types": "./src/schema/index.ts",
|
|
120
|
+
"default": "./src/schema/index.ts"
|
|
121
|
+
},
|
|
122
|
+
"./schema/zod": {
|
|
123
|
+
"types": "./src/schema/drivers/zod.ts",
|
|
124
|
+
"default": "./src/schema/drivers/zod.ts"
|
|
125
|
+
},
|
|
126
|
+
"./schema/openapi": {
|
|
127
|
+
"types": "./src/schema/openapi.ts",
|
|
128
|
+
"default": "./src/schema/openapi.ts"
|
|
129
|
+
},
|
|
130
|
+
"./server": {
|
|
131
|
+
"types": "./src/server/index.ts",
|
|
132
|
+
"default": "./src/server/index.ts"
|
|
133
|
+
},
|
|
134
|
+
"./server/fastify": {
|
|
135
|
+
"types": "./src/server/drivers/fastify.ts",
|
|
136
|
+
"default": "./src/server/drivers/fastify.ts"
|
|
137
|
+
},
|
|
138
|
+
"./server/node": {
|
|
139
|
+
"types": "./src/server/drivers/node.ts",
|
|
140
|
+
"default": "./src/server/drivers/node.ts"
|
|
141
|
+
},
|
|
142
|
+
"./ui": {
|
|
143
|
+
"types": "./src/ui/index.ts",
|
|
144
|
+
"default": "./src/ui/index.ts"
|
|
145
|
+
},
|
|
146
|
+
"./ui/react": {
|
|
147
|
+
"types": "./src/ui/react.tsx",
|
|
148
|
+
"default": "./src/ui/react.tsx"
|
|
149
|
+
},
|
|
150
|
+
"./ui/meta": {
|
|
151
|
+
"types": "./src/ui/meta.ts",
|
|
152
|
+
"default": "./src/ui/meta.ts"
|
|
153
|
+
},
|
|
154
|
+
"./ui/docs": {
|
|
155
|
+
"types": "./src/ui/docs/index.ts",
|
|
156
|
+
"default": "./src/ui/docs/index.ts"
|
|
157
|
+
},
|
|
158
|
+
"./ui/docs/standalone": {
|
|
159
|
+
"types": "./src/ui/docs/standalone.tsx",
|
|
160
|
+
"default": "./src/ui/docs/standalone.tsx"
|
|
161
|
+
},
|
|
162
|
+
"./ui/docs/plugin": {
|
|
163
|
+
"types": "./src/ui/docs/plugin.ts",
|
|
164
|
+
"default": "./src/ui/docs/plugin.ts"
|
|
165
|
+
},
|
|
166
|
+
"./vite": {
|
|
167
|
+
"types": "./src/vite/index.ts",
|
|
168
|
+
"default": "./src/vite/index.ts"
|
|
169
|
+
},
|
|
170
|
+
"./ui/theme.css": "./src/ui/theme.css"
|
|
171
|
+
},
|
|
172
|
+
"files": [
|
|
173
|
+
"src",
|
|
174
|
+
"registry",
|
|
175
|
+
"bin",
|
|
176
|
+
"docs",
|
|
177
|
+
"README.md",
|
|
178
|
+
"CHANGELOG.md",
|
|
179
|
+
"LICENSE"
|
|
180
|
+
],
|
|
181
|
+
"publishConfig": {
|
|
182
|
+
"registry": "https://registry.npmjs.org/",
|
|
183
|
+
"access": "public"
|
|
184
|
+
},
|
|
185
|
+
"bin": {
|
|
186
|
+
"opus": "./bin/cli.mjs"
|
|
187
|
+
},
|
|
188
|
+
"dependencies": {
|
|
189
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
190
|
+
"@radix-ui/react-checkbox": "^1.1.3",
|
|
191
|
+
"@radix-ui/react-dialog": "^1.1.4",
|
|
192
|
+
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
193
|
+
"@radix-ui/react-label": "^2.1.1",
|
|
194
|
+
"@radix-ui/react-popover": "^1.1.4",
|
|
195
|
+
"@radix-ui/react-separator": "^1.1.2",
|
|
196
|
+
"@radix-ui/react-slot": "^1.1.1",
|
|
197
|
+
"@radix-ui/react-tabs": "^1.1.2",
|
|
198
|
+
"@radix-ui/react-tooltip": "^1.1.6",
|
|
199
|
+
"@tailwindcss/typography": "^0.5.20",
|
|
200
|
+
"@types/markdown-it": "^14.1.2",
|
|
201
|
+
"class-variance-authority": "^0.7.1",
|
|
202
|
+
"clsx": "^2.1.1",
|
|
203
|
+
"cmdk": "^1.1.1",
|
|
204
|
+
"date-fns": "^4.4.0",
|
|
205
|
+
"embla-carousel-react": "^8.6.0",
|
|
206
|
+
"input-otp": "^1.4.2",
|
|
207
|
+
"lucide-react": "^0.460.0",
|
|
208
|
+
"markdown-it": "^14.2.0",
|
|
209
|
+
"mitt": "^3.0.1",
|
|
210
|
+
"prism-react-renderer": "^2.4.1",
|
|
211
|
+
"radix-ui": "^1.6.0",
|
|
212
|
+
"react-day-picker": "^10.0.1",
|
|
213
|
+
"react-resizable-panels": "^4.11.2",
|
|
214
|
+
"sonner": "^1.7.1",
|
|
215
|
+
"sucrase": "^3.35.1",
|
|
216
|
+
"tailwind-merge": "^3.3.1",
|
|
217
|
+
"tw-animate-css": "^1.2.5",
|
|
218
|
+
"typescript": "^5.6.0",
|
|
219
|
+
"zod-to-json-schema": "^3.23.0"
|
|
220
|
+
},
|
|
221
|
+
"peerDependencies": {
|
|
222
|
+
"@anthropic-ai/sdk": ">=0.35.0",
|
|
223
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
224
|
+
"@aws-sdk/s3-request-presigner": "^3.0.0",
|
|
225
|
+
"@hookform/resolvers": "^3.0.0",
|
|
226
|
+
"@tanstack/react-query": "^5.0.0",
|
|
227
|
+
"bullmq": "^5.0.0",
|
|
228
|
+
"fastify": "^5.0.0",
|
|
229
|
+
"jsonwebtoken": "^9.0.0",
|
|
230
|
+
"kysely": "^0.27.0",
|
|
231
|
+
"node-cron": "^3.0.0",
|
|
232
|
+
"pg": "^8.0.0",
|
|
233
|
+
"pino": "^9.0.0",
|
|
234
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
235
|
+
"react-hook-form": "^7.0.0",
|
|
236
|
+
"vite": "^5.0.0 || ^6.0.0",
|
|
237
|
+
"zod": "^3.24.0"
|
|
238
|
+
},
|
|
239
|
+
"peerDependenciesMeta": {
|
|
240
|
+
"@hookform/resolvers": {
|
|
241
|
+
"optional": true
|
|
242
|
+
},
|
|
243
|
+
"@tanstack/react-query": {
|
|
244
|
+
"optional": true
|
|
245
|
+
},
|
|
246
|
+
"bullmq": {
|
|
247
|
+
"optional": true
|
|
248
|
+
},
|
|
249
|
+
"fastify": {
|
|
250
|
+
"optional": true
|
|
251
|
+
},
|
|
252
|
+
"jsonwebtoken": {
|
|
253
|
+
"optional": true
|
|
254
|
+
},
|
|
255
|
+
"kysely": {
|
|
256
|
+
"optional": true
|
|
257
|
+
},
|
|
258
|
+
"node-cron": {
|
|
259
|
+
"optional": true
|
|
260
|
+
},
|
|
261
|
+
"pg": {
|
|
262
|
+
"optional": true
|
|
263
|
+
},
|
|
264
|
+
"react-hook-form": {
|
|
265
|
+
"optional": true
|
|
266
|
+
},
|
|
267
|
+
"pino": {
|
|
268
|
+
"optional": true
|
|
269
|
+
},
|
|
270
|
+
"react": {
|
|
271
|
+
"optional": true
|
|
272
|
+
},
|
|
273
|
+
"vite": {
|
|
274
|
+
"optional": true
|
|
275
|
+
},
|
|
276
|
+
"zod": {
|
|
277
|
+
"optional": true
|
|
278
|
+
},
|
|
279
|
+
"@aws-sdk/client-s3": {
|
|
280
|
+
"optional": true
|
|
281
|
+
},
|
|
282
|
+
"@aws-sdk/s3-request-presigner": {
|
|
283
|
+
"optional": true
|
|
284
|
+
},
|
|
285
|
+
"@anthropic-ai/sdk": {
|
|
286
|
+
"optional": true
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
"devDependencies": {
|
|
290
|
+
"@anthropic-ai/sdk": ">=0.35.0",
|
|
291
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
292
|
+
"@aws-sdk/s3-request-presigner": "^3.0.0",
|
|
293
|
+
"@hookform/resolvers": "^3.10.0",
|
|
294
|
+
"@tanstack/react-query": "^5.62.0",
|
|
295
|
+
"@testing-library/dom": "^10.4.0",
|
|
296
|
+
"@testing-library/react": "^16.1.0",
|
|
297
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
298
|
+
"@types/jsonwebtoken": "^9.0.0",
|
|
299
|
+
"@types/node": "^22.0.0",
|
|
300
|
+
"@types/node-cron": "^3.0.0",
|
|
301
|
+
"@types/pg": "^8.11.0",
|
|
302
|
+
"@types/react": "^19.0.0",
|
|
303
|
+
"@types/react-dom": "^19.0.0",
|
|
304
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
305
|
+
"better-sqlite3": "^11.0.0",
|
|
306
|
+
"bullmq": "^5.0.0",
|
|
307
|
+
"fastify": "^5.0.0",
|
|
308
|
+
"happy-dom": "^15.11.0",
|
|
309
|
+
"jsonwebtoken": "^9.0.2",
|
|
310
|
+
"kysely": "^0.27.0",
|
|
311
|
+
"node-cron": "^3.0.3",
|
|
312
|
+
"pg": "^8.13.0",
|
|
313
|
+
"pino": "^9.5.0",
|
|
314
|
+
"react": "^19.0.0",
|
|
315
|
+
"react-dom": "^19.0.0",
|
|
316
|
+
"react-hook-form": "^7.54.0",
|
|
317
|
+
"tsx": "^4.19.0",
|
|
318
|
+
"vite": "^6.0.0",
|
|
319
|
+
"vitest": "^2.1.0",
|
|
320
|
+
"zod": "^3.24.0"
|
|
321
|
+
},
|
|
322
|
+
"repository": {
|
|
323
|
+
"type": "git",
|
|
324
|
+
"url": "git+https://github.com/softize-dev/opus.git",
|
|
325
|
+
"directory": "packages/opus"
|
|
326
|
+
},
|
|
327
|
+
"homepage": "https://opus.softize.com.br",
|
|
328
|
+
"scripts": {
|
|
329
|
+
"postinstall": "node ./bin/lib/postinstall.mjs",
|
|
330
|
+
"typecheck": "tsc --noEmit",
|
|
331
|
+
"test": "vitest run",
|
|
332
|
+
"test:watch": "vitest",
|
|
333
|
+
"test:cov": "vitest run --coverage",
|
|
334
|
+
"registry:up": "npx -y verdaccio --config ~/.config/verdaccio/config.yaml",
|
|
335
|
+
"release": "bash ./scripts/release.sh",
|
|
336
|
+
"release:local": "bash ./scripts/release.sh --local"
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/link-memory-on-start.mjs\"",
|
|
9
|
+
"timeout": 10
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"Stop": [
|
|
15
|
+
{
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/opus-check-on-stop.mjs\"",
|
|
20
|
+
"timeout": 120
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook SessionStart da base Opus: liga a memória versionada do repo
|
|
3
|
+
* (`.claude/memory`, política da skill `memory`) ao diretório que o Claude Code
|
|
4
|
+
* lê (`~/.claude/projects/<hash>/memory`). Sem isso, sessão em worktree/máquina
|
|
5
|
+
* nova roda AMNÉSICA — recall vazio e memória gravada num diretório órfão que
|
|
6
|
+
* morre com o worktree. É o `link-memory.sh` automatizado: idempotente, com
|
|
7
|
+
* backup de memória local pré-existente, e fail-open (repo sem `.claude/memory`
|
|
8
|
+
* versionado → no-op; qualquer erro → segue sem travar a sessão).
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, renameSync, rmdirSync, symlinkSync, unlinkSync } from 'node:fs'
|
|
11
|
+
import { homedir } from 'node:os'
|
|
12
|
+
import { dirname, join } from 'node:path'
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const root = process.env.CLAUDE_PROJECT_DIR ?? process.cwd()
|
|
16
|
+
const memRepo = join(root, '.claude', 'memory')
|
|
17
|
+
// Sem memória versionada → o repo não adota a política; nada a ligar.
|
|
18
|
+
if (!existsSync(memRepo)) process.exit(0)
|
|
19
|
+
|
|
20
|
+
// O hash do projeto é o caminho absoluto com separadores (e pontos) virando '-',
|
|
21
|
+
// como o Claude Code nomeia ~/.claude/projects/. Espelha o link-memory.sh.
|
|
22
|
+
const hash = root.replace(/[/.]/g, '-')
|
|
23
|
+
const dest = join(homedir(), '.claude', 'projects', hash, 'memory')
|
|
24
|
+
|
|
25
|
+
let st = null
|
|
26
|
+
try {
|
|
27
|
+
st = lstatSync(dest)
|
|
28
|
+
} catch {
|
|
29
|
+
/* Não existe → segue pro link. */
|
|
30
|
+
}
|
|
31
|
+
if (st?.isSymbolicLink()) {
|
|
32
|
+
if (readlinkSync(dest) === memRepo) process.exit(0) // Já ligado.
|
|
33
|
+
unlinkSync(dest) // Aponta pra outro lugar → religa.
|
|
34
|
+
} else if (st?.isDirectory()) {
|
|
35
|
+
// Memória local pré-existente: com conteúdo → backup (nunca descarta); vazia → sai.
|
|
36
|
+
if (readdirSync(dest).length > 0) renameSync(dest, `${dest}.local-${Date.now()}`)
|
|
37
|
+
else rmdirSync(dest)
|
|
38
|
+
} else if (st !== null) {
|
|
39
|
+
unlinkSync(dest) // Arquivo solto no lugar do diretório — afasta.
|
|
40
|
+
}
|
|
41
|
+
mkdirSync(dirname(dest), { recursive: true })
|
|
42
|
+
symlinkSync(memRepo, dest)
|
|
43
|
+
} catch {
|
|
44
|
+
/* Fail-open: memória desligada é degradação, não motivo pra travar a sessão. */
|
|
45
|
+
}
|
|
46
|
+
process.exit(0)
|