@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.
Files changed (286) hide show
  1. package/CHANGELOG.md +1616 -0
  2. package/LICENSE +21 -0
  3. package/README.md +113 -0
  4. package/bin/cli.mjs +528 -0
  5. package/bin/lib/check.mjs +307 -0
  6. package/bin/lib/components.mjs +151 -0
  7. package/bin/lib/create.mjs +208 -0
  8. package/bin/lib/db-check-runner.mjs +86 -0
  9. package/bin/lib/db-migrate-runner.mjs +89 -0
  10. package/bin/lib/db-scaffold-runner.mjs +84 -0
  11. package/bin/lib/db.mjs +261 -0
  12. package/bin/lib/docs-include.mjs +48 -0
  13. package/bin/lib/gen-dicts.mjs +134 -0
  14. package/bin/lib/gen-docs.mjs +288 -0
  15. package/bin/lib/gen-manifest.mjs +102 -0
  16. package/bin/lib/gen-openapi.mjs +195 -0
  17. package/bin/lib/gen-runner.mjs +472 -0
  18. package/bin/lib/gen-stubs.mjs +463 -0
  19. package/bin/lib/gen.mjs +311 -0
  20. package/bin/lib/init.mjs +514 -0
  21. package/bin/lib/introspect.mjs +107 -0
  22. package/bin/lib/mcp.mjs +85 -0
  23. package/bin/lib/postinstall.mjs +56 -0
  24. package/docs/chat-event-protocol.md +85 -0
  25. package/docs/code-style.md +16 -0
  26. package/docs/data-layer.md +246 -0
  27. package/docs/ownership-vs-shadcn-lock.md +102 -0
  28. package/docs/protocol.md +2053 -0
  29. package/docs/releasing.md +110 -0
  30. package/docs/shellnav.md +131 -0
  31. package/package.json +338 -0
  32. package/registry/hooks/hooks.json +26 -0
  33. package/registry/hooks/link-memory-on-start.mjs +46 -0
  34. package/registry/hooks/opus-check-on-stop.mjs +114 -0
  35. package/registry/skills/create-action/SKILL.md +49 -0
  36. package/registry/skills/create-action/scaffold.mjs +122 -0
  37. package/registry/templates/app/_gitignore +3 -0
  38. package/registry/templates/app/_npmrc +1 -0
  39. package/registry/templates/app/_opus/_gitignore +5 -0
  40. package/registry/templates/app/_prettierrc.json +6 -0
  41. package/registry/templates/app/index.html +13 -0
  42. package/registry/templates/app/opus.config.ts +16 -0
  43. package/registry/templates/app/package.json +43 -0
  44. package/registry/templates/app/pnpm-workspace.yaml +11 -0
  45. package/registry/templates/app/public/favicon.svg +4 -0
  46. package/registry/templates/app/src/App.tsx +37 -0
  47. package/registry/templates/app/src/domains/tasks/actions/list.test.ts +34 -0
  48. package/registry/templates/app/src/domains/tasks/actions/list.ts +33 -0
  49. package/registry/templates/app/src/domains/tasks/index.ts +13 -0
  50. package/registry/templates/app/src/index.css +18 -0
  51. package/registry/templates/app/src/main.tsx +25 -0
  52. package/registry/templates/app/tsconfig.json +20 -0
  53. package/registry/templates/app/vite.config.ts +46 -0
  54. package/registry/templates/monorepo/_gitignore +3 -0
  55. package/registry/templates/monorepo/_npmrc +1 -0
  56. package/registry/templates/monorepo/package.json +9 -0
  57. package/registry/templates/monorepo/pnpm-workspace.yaml +14 -0
  58. package/src/ai/ask.ts +64 -0
  59. package/src/ai/drivers/anthropic.ts +309 -0
  60. package/src/ai/index.ts +17 -0
  61. package/src/audit/drivers/console.ts +117 -0
  62. package/src/audit/drivers/pg.ts +172 -0
  63. package/src/audit/index.ts +51 -0
  64. package/src/auth/drivers/better-auth.ts +103 -0
  65. package/src/auth/drivers/jwt.ts +188 -0
  66. package/src/auth/index.ts +9 -0
  67. package/src/client/drivers/fetch.ts +202 -0
  68. package/src/client/index.ts +22 -0
  69. package/src/core/actions.ts +110 -0
  70. package/src/core/audit.ts +239 -0
  71. package/src/core/contracts.ts +137 -0
  72. package/src/core/domain.ts +310 -0
  73. package/src/core/errors.ts +181 -0
  74. package/src/core/index.ts +174 -0
  75. package/src/core/logical-type.ts +31 -0
  76. package/src/core/reactions.ts +81 -0
  77. package/src/core/runtime.ts +1167 -0
  78. package/src/core/schedules.ts +41 -0
  79. package/src/core/types.ts +1356 -0
  80. package/src/data/drivers/kysely.ts +389 -0
  81. package/src/data/index.ts +10 -0
  82. package/src/data/readonly-pool.ts +160 -0
  83. package/src/dsl/eval.ts +136 -0
  84. package/src/dsl/index.ts +29 -0
  85. package/src/dsl/kysely.ts +230 -0
  86. package/src/dsl/loads.ts +123 -0
  87. package/src/dsl/parser.ts +423 -0
  88. package/src/dsl/types.ts +113 -0
  89. package/src/events/drivers/mitt.ts +70 -0
  90. package/src/events/index.ts +9 -0
  91. package/src/log/drivers/pino.ts +57 -0
  92. package/src/log/index.ts +9 -0
  93. package/src/mcp/index.ts +62 -0
  94. package/src/queue/drivers/bullmq.ts +190 -0
  95. package/src/queue/index.ts +9 -0
  96. package/src/scheduler/drivers/node-cron.ts +93 -0
  97. package/src/scheduler/every.ts +45 -0
  98. package/src/scheduler/index.ts +9 -0
  99. package/src/schema/drivers/zod.ts +765 -0
  100. package/src/schema/entity.ts +439 -0
  101. package/src/schema/format/locale.ts +144 -0
  102. package/src/schema/index.ts +65 -0
  103. package/src/schema/openapi.ts +302 -0
  104. package/src/schema/scaffold.ts +160 -0
  105. package/src/server/drivers/fastify.ts +224 -0
  106. package/src/server/drivers/node.ts +386 -0
  107. package/src/server/index.ts +142 -0
  108. package/src/storage/drivers/fs.ts +90 -0
  109. package/src/storage/drivers/s3.ts +117 -0
  110. package/src/storage/index.ts +27 -0
  111. package/src/testing/fake.ts +298 -0
  112. package/src/testing/index.ts +324 -0
  113. package/src/ui/components/patterns/action-form-card.tsx +48 -0
  114. package/src/ui/components/patterns/action-list-dialog.tsx +93 -0
  115. package/src/ui/components/patterns/app-shell.tsx +227 -0
  116. package/src/ui/components/patterns/confirm.tsx +226 -0
  117. package/src/ui/components/patterns/data-state.tsx +75 -0
  118. package/src/ui/components/patterns/form-dialog.tsx +64 -0
  119. package/src/ui/components/patterns/form.tsx +584 -0
  120. package/src/ui/components/patterns/list.tsx +1488 -0
  121. package/src/ui/components/patterns/page.tsx +46 -0
  122. package/src/ui/components/patterns/section-shell.tsx +246 -0
  123. package/src/ui/components/patterns/shell-nav.tsx +150 -0
  124. package/src/ui/components/patterns/sidebar.tsx +89 -0
  125. package/src/ui/components/patterns/split.tsx +93 -0
  126. package/src/ui/components/patterns/trigger.tsx +196 -0
  127. package/src/ui/components/patterns/view.tsx +84 -0
  128. package/src/ui/components/primitives/accordion.tsx +64 -0
  129. package/src/ui/components/primitives/alert-dialog.tsx +190 -0
  130. package/src/ui/components/primitives/alert.tsx +116 -0
  131. package/src/ui/components/primitives/aspect-ratio.tsx +9 -0
  132. package/src/ui/components/primitives/avatar.tsx +107 -0
  133. package/src/ui/components/primitives/badge.tsx +37 -0
  134. package/src/ui/components/primitives/breadcrumb.tsx +109 -0
  135. package/src/ui/components/primitives/button-group.tsx +83 -0
  136. package/src/ui/components/primitives/button.tsx +102 -0
  137. package/src/ui/components/primitives/calendar.tsx +218 -0
  138. package/src/ui/components/primitives/card.tsx +56 -0
  139. package/src/ui/components/primitives/carousel.tsx +239 -0
  140. package/src/ui/components/primitives/chat.tsx +407 -0
  141. package/src/ui/components/primitives/checkbox.tsx +30 -0
  142. package/src/ui/components/primitives/collapsible.tsx +31 -0
  143. package/src/ui/components/primitives/command.tsx +182 -0
  144. package/src/ui/components/primitives/composer.tsx +121 -0
  145. package/src/ui/components/primitives/copyable.tsx +50 -0
  146. package/src/ui/components/primitives/dialog.tsx +147 -0
  147. package/src/ui/components/primitives/drawer.tsx +141 -0
  148. package/src/ui/components/primitives/empty.tsx +104 -0
  149. package/src/ui/components/primitives/field.tsx +246 -0
  150. package/src/ui/components/primitives/icon-picker.tsx +180 -0
  151. package/src/ui/components/primitives/input-group.tsx +168 -0
  152. package/src/ui/components/primitives/input-otp.tsx +75 -0
  153. package/src/ui/components/primitives/input.tsx +72 -0
  154. package/src/ui/components/primitives/item.tsx +193 -0
  155. package/src/ui/components/primitives/kbd.tsx +28 -0
  156. package/src/ui/components/primitives/label.tsx +22 -0
  157. package/src/ui/components/primitives/markdown.tsx +35 -0
  158. package/src/ui/components/primitives/menu.tsx +255 -0
  159. package/src/ui/components/primitives/pagination.tsx +127 -0
  160. package/src/ui/components/primitives/popover.tsx +87 -0
  161. package/src/ui/components/primitives/progress.tsx +29 -0
  162. package/src/ui/components/primitives/radio-group.tsx +43 -0
  163. package/src/ui/components/primitives/resizable.tsx +51 -0
  164. package/src/ui/components/primitives/scroll-area.tsx +56 -0
  165. package/src/ui/components/primitives/select.tsx +479 -0
  166. package/src/ui/components/primitives/separator.tsx +26 -0
  167. package/src/ui/components/primitives/skeleton.tsx +13 -0
  168. package/src/ui/components/primitives/slider.tsx +61 -0
  169. package/src/ui/components/primitives/sonner.tsx +46 -0
  170. package/src/ui/components/primitives/spinner.tsx +29 -0
  171. package/src/ui/components/primitives/switch.tsx +33 -0
  172. package/src/ui/components/primitives/table.tsx +114 -0
  173. package/src/ui/components/primitives/tabs.tsx +104 -0
  174. package/src/ui/components/primitives/textarea.tsx +18 -0
  175. package/src/ui/components/primitives/toggle-group.tsx +81 -0
  176. package/src/ui/components/primitives/toggle.tsx +45 -0
  177. package/src/ui/components/primitives/tooltip.tsx +55 -0
  178. package/src/ui/components/primitives/truncate.tsx +49 -0
  179. package/src/ui/docs/DocBrowser.tsx +90 -0
  180. package/src/ui/docs/changelog.tsx +80 -0
  181. package/src/ui/docs/content/accordion.md +86 -0
  182. package/src/ui/docs/content/action-form-card.md +24 -0
  183. package/src/ui/docs/content/action-form-dialog.md +30 -0
  184. package/src/ui/docs/content/action-form.md +125 -0
  185. package/src/ui/docs/content/action-list-dialog.md +68 -0
  186. package/src/ui/docs/content/action-list.md +194 -0
  187. package/src/ui/docs/content/action-trigger.md +72 -0
  188. package/src/ui/docs/content/action-view.md +47 -0
  189. package/src/ui/docs/content/actions.md +138 -0
  190. package/src/ui/docs/content/ai.md +112 -0
  191. package/src/ui/docs/content/alert-dialog.md +73 -0
  192. package/src/ui/docs/content/alert.md +69 -0
  193. package/src/ui/docs/content/app-shell.md +155 -0
  194. package/src/ui/docs/content/aspect-ratio.md +66 -0
  195. package/src/ui/docs/content/audit.md +84 -0
  196. package/src/ui/docs/content/auth.md +70 -0
  197. package/src/ui/docs/content/avatar.md +94 -0
  198. package/src/ui/docs/content/badge.md +48 -0
  199. package/src/ui/docs/content/breadcrumb.md +87 -0
  200. package/src/ui/docs/content/button-group.md +71 -0
  201. package/src/ui/docs/content/button.md +60 -0
  202. package/src/ui/docs/content/calendar.md +62 -0
  203. package/src/ui/docs/content/card.md +49 -0
  204. package/src/ui/docs/content/carousel.md +85 -0
  205. package/src/ui/docs/content/chat.md +69 -0
  206. package/src/ui/docs/content/checkbox.md +75 -0
  207. package/src/ui/docs/content/cli.md +58 -0
  208. package/src/ui/docs/content/collapsible.md +64 -0
  209. package/src/ui/docs/content/command.md +56 -0
  210. package/src/ui/docs/content/composer.md +50 -0
  211. package/src/ui/docs/content/confirm.md +120 -0
  212. package/src/ui/docs/content/copyable.md +30 -0
  213. package/src/ui/docs/content/customization.md +110 -0
  214. package/src/ui/docs/content/cycle.md +34 -0
  215. package/src/ui/docs/content/data-state.md +47 -0
  216. package/src/ui/docs/content/data.md +99 -0
  217. package/src/ui/docs/content/dialog.md +60 -0
  218. package/src/ui/docs/content/drawer.md +55 -0
  219. package/src/ui/docs/content/empty.md +66 -0
  220. package/src/ui/docs/content/events.md +61 -0
  221. package/src/ui/docs/content/field.md +58 -0
  222. package/src/ui/docs/content/getting-started.md +109 -0
  223. package/src/ui/docs/content/icon-picker.md +51 -0
  224. package/src/ui/docs/content/input-group.md +78 -0
  225. package/src/ui/docs/content/input-otp.md +72 -0
  226. package/src/ui/docs/content/input.md +78 -0
  227. package/src/ui/docs/content/item.md +84 -0
  228. package/src/ui/docs/content/kbd.md +62 -0
  229. package/src/ui/docs/content/label.md +32 -0
  230. package/src/ui/docs/content/log.md +55 -0
  231. package/src/ui/docs/content/markdown.md +41 -0
  232. package/src/ui/docs/content/mcp.md +44 -0
  233. package/src/ui/docs/content/menu.md +114 -0
  234. package/src/ui/docs/content/microcopy.md +83 -0
  235. package/src/ui/docs/content/page.md +34 -0
  236. package/src/ui/docs/content/pagination.md +99 -0
  237. package/src/ui/docs/content/popover.md +49 -0
  238. package/src/ui/docs/content/progress.md +69 -0
  239. package/src/ui/docs/content/queue.md +62 -0
  240. package/src/ui/docs/content/radio-group.md +77 -0
  241. package/src/ui/docs/content/resizable.md +86 -0
  242. package/src/ui/docs/content/router.md +56 -0
  243. package/src/ui/docs/content/runtime.md +77 -0
  244. package/src/ui/docs/content/scheduler.md +66 -0
  245. package/src/ui/docs/content/scroll-area.md +89 -0
  246. package/src/ui/docs/content/section-shell.md +121 -0
  247. package/src/ui/docs/content/select.md +342 -0
  248. package/src/ui/docs/content/separator.md +33 -0
  249. package/src/ui/docs/content/sidebar.md +38 -0
  250. package/src/ui/docs/content/skeleton.md +34 -0
  251. package/src/ui/docs/content/slider.md +64 -0
  252. package/src/ui/docs/content/spinner.md +37 -0
  253. package/src/ui/docs/content/split.md +33 -0
  254. package/src/ui/docs/content/storage.md +69 -0
  255. package/src/ui/docs/content/switch.md +69 -0
  256. package/src/ui/docs/content/table.md +102 -0
  257. package/src/ui/docs/content/tabs.md +94 -0
  258. package/src/ui/docs/content/testing.md +89 -0
  259. package/src/ui/docs/content/textarea.md +30 -0
  260. package/src/ui/docs/content/toast.md +67 -0
  261. package/src/ui/docs/content/toggle-group.md +81 -0
  262. package/src/ui/docs/content/toggle.md +72 -0
  263. package/src/ui/docs/content/tokens.md +171 -0
  264. package/src/ui/docs/content/tooltip.md +50 -0
  265. package/src/ui/docs/content/truncate.md +37 -0
  266. package/src/ui/docs/content/ui.md +40 -0
  267. package/src/ui/docs/content/upgrading.md +48 -0
  268. package/src/ui/docs/doc-client.tsx +214 -0
  269. package/src/ui/docs/doc.tsx +301 -0
  270. package/src/ui/docs/folder.tsx +149 -0
  271. package/src/ui/docs/index.ts +21 -0
  272. package/src/ui/docs/markdown.tsx +130 -0
  273. package/src/ui/docs/md-raw.d.ts +4 -0
  274. package/src/ui/docs/plugin.ts +104 -0
  275. package/src/ui/docs/registry.tsx +424 -0
  276. package/src/ui/docs/standalone.tsx +107 -0
  277. package/src/ui/drivers/react.tsx +627 -0
  278. package/src/ui/index.ts +92 -0
  279. package/src/ui/lib/cn.ts +10 -0
  280. package/src/ui/lib/zod-pt-br.ts +38 -0
  281. package/src/ui/meta.ts +412 -0
  282. package/src/ui/react.tsx +235 -0
  283. package/src/ui/router.ts +96 -0
  284. package/src/ui/theme.css +234 -0
  285. package/src/vite/design.ts +652 -0
  286. package/src/vite/index.ts +8 -0
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: Getting started
3
+ ---
4
+
5
+ # Getting started
6
+
7
+ O Opus é um SDK/protocolo spec-driven: o domínio **É** a aplicação (contratos +
8
+ actions); front e back são cascas. Um projeto Opus-based pina o Opus, herda o runtime e segue os gates.
9
+
10
+ ## O modelo
11
+
12
+ > Antes de qualquer arquivo: por que o Opus existe e o que ele assume.
13
+
14
+ A aplicação é o **domínio** — entidades, dicts e contratos de action. A API e a web são cascas
15
+ que consomem esse domínio: zero shape duplicado. O Opus entrega o núcleo (runtime, adapters, UI,
16
+ CLI) e os gates que mantêm o padrão. O que cada projeto adiciona é o seu domínio; o resto vem pinado.
17
+
18
+ ## Começar do zero
19
+
20
+ > Projeto novo não se monta à mão: o esqueleto canônico sai do `opus create`, com os
21
+ > pré-requisitos do protocolo, da UI e do preview já plugados — e os gates verdes.
22
+
23
+ O Opus mora no registry da Softize (não no npm público) — uma vez por máquina, ensine
24
+ o escopo ao pnpm; dentro do projeto criado o `.npmrc` já cuida disso:
25
+
26
+ ```bash
27
+ pnpm config set @softize:registry https://registry.softize.com.br/ --global # 1x por máquina
28
+
29
+ pnpm dlx @softize/opus create meu-app
30
+ cd meu-app && git init && pnpm install && pnpm test
31
+ ```
32
+
33
+ Máquina nova: se o pnpm reclamar que o diretório global de binários não está no PATH
34
+ (o `dlx` exige), rode `pnpm setup` e reabra o terminal — também é 1x por máquina. Se o
35
+ setup acusar seção pnpm antiga no shell rc (`ERR_PNPM_BAD_SHELL_SECTION`), é resquício
36
+ de versão anterior: `pnpm setup --force` substitui só o bloco dele.
37
+
38
+ Release recém-saída (menos de 24h): a quarentena do pnpm resolve o `dlx` pra versão
39
+ ANTIGA em silêncio ("Comando desconhecido" = sintoma clássico). Fure com a versão
40
+ explícita — `pnpm dlx @softize/opus@<versão> create meu-app` — ou com a flag
41
+ `pnpm --config.minimum-release-age=0 dlx …`. Dentro de projeto o pnpm se resolve
42
+ sozinho (auto-exclui o Opus da quarentena no install).
43
+
44
+ Nasce com: `opus.config.ts` + domínio-exemplo canônico (0 violações, spec documentada),
45
+ vite + react + tema do Opus (Tailwind v4 CSS-first), dev server na porta que o Maestro
46
+ injeta no preview, `opus.json` (pin), `CLAUDE.md` (bloco gerenciado), `.claude/memory/`
47
+ e o CI de fábrica.
48
+
49
+ **Monorepo:** a raiz nasce do `--monorepo` e cada app nasce dentro dela — o create
50
+ detecta o `pnpm-workspace.yaml` e gera só o que é do app (nada de `.npmrc`/workspace
51
+ yaml aninhado), **avisando** o que a raiz precisa ter (glob de packages, escopo do
52
+ registry, allowBuilds) sem tocar nos seus arquivos:
53
+
54
+ ```bash
55
+ pnpm dlx @softize/opus create meu-cliente --monorepo # a raiz do workspace
56
+ cd meu-cliente && git init
57
+ pnpm dlx @softize/opus create apps/portal # o app (modo detectado)
58
+ ```
59
+
60
+ ## Carregar o Opus num projeto existente
61
+
62
+ > O pin vive no `opus.json`; o setup grava o esqueleto local. Ausência de `opus.json` = projeto
63
+ > não inicializado — não improvise, rode o setup.
64
+
65
+ A versão do Opus fica pinada em `opus.json`. O `opus setup` é per-app: grava o `opus.json`,
66
+ mantém o bloco gerenciado do `CLAUDE.md` (fora dele o arquivo é seu) e semeia o dia zero
67
+ (`.claude/memory/`, CI) se faltarem. Os componentes e hooks vêm do barrel
68
+ `@softize/opus/ui/react`; o tema, por CSS.
69
+
70
+ ```bash
71
+ # Bootstrap per-app (idempotente): pin + bloco do CLAUDE.md + dia zero.
72
+ npx @softize/opus setup
73
+
74
+ # index.css do app — o tema canônico + os componentes do Opus no scan do Tailwind.
75
+ @import '@softize/opus/ui/theme.css';
76
+ @source '../node_modules/@softize/opus/src/ui/**/*.{ts,tsx}';
77
+ ```
78
+
79
+ ## A stack do runtime
80
+
81
+ > `createRuntime` compõe a stack a partir de adapters plugáveis. Cada capacidade (data, auth,
82
+ > audit…) é um adapter — troca a implementação sem tocar o domínio.
83
+
84
+ ```ts
85
+ import { createRuntime } from '@softize/opus/core'
86
+ import { kyselyData } from '@softize/opus/data/kysely'
87
+ import { fastifyServer } from '@softize/opus/server/fastify'
88
+ import { pgAudit } from '@softize/opus/audit/pg'
89
+
90
+ const runtime = createRuntime({
91
+ server: fastifyServer({ app }),
92
+ data: kyselyData({ db }), // Kysely + Postgres
93
+ auth: makeAuthAdapter(), // gate (IdP)
94
+ audit: [pgAudit({ pool })], // trilha de auditoria
95
+ config: { env, i18n: { defaultLocale: 'pt-BR' } },
96
+ })
97
+
98
+ // Domínios = grupos de actions. Não registrado = não existe.
99
+ runtime.register([workspacesDomain, agentsDomain, skillsDomain])
100
+ await runtime.start()
101
+ ```
102
+
103
+ ## Antes de mexer
104
+
105
+ > O protocolo de leitura: a verdade local mora nos docs do repo, não nesta página.
106
+
107
+ - `CLAUDE.md` do repo e do app — o índice local: mapa, gates, gotchas.
108
+ - As `description` das entidades/actions — a spec de negócio, projetada no manifest pelo `opus gen`.
109
+ - Gate de build: `opus check` (convenções das actions) + `opus db check` (drift entidade ↔ banco). Rode antes de entregar.
@@ -0,0 +1,51 @@
1
+ O value é o **nome** do ícone (kebab-case, chave da paleta) — quem consome renderiza com a mesma paleta: `iconPickerIcons[name] ?? FallbackIcon`. Selecionar o já-escolhido desmarca (volta a `''`).
2
+
3
+ ## Básico
4
+
5
+ ```tsx preview col md
6
+ const [icon, setIcon] = useState('chart-line')
7
+
8
+ render(
9
+ <div className="grid gap-2">
10
+ <Label htmlFor="report-icon">Ícone do relatório</Label>
11
+ <IconPicker id="report-icon" value={icon} onChange={setIcon} />
12
+ </div>,
13
+ )
14
+ ```
15
+
16
+ ## Renderizando o escolhido
17
+
18
+ A paleta default é exportada (`iconPickerIcons`) — use-a pra desenhar o ícone salvo onde ele aparece (item de lista, card, árvore).
19
+
20
+ ```tsx preview col md
21
+ const [icon, setIcon] = useState('store')
22
+ const Icon = iconPickerIcons[icon] ?? FileText
23
+
24
+ render(
25
+ <div className="flex items-center gap-3">
26
+ <IconPicker value={icon} onChange={setIcon} className="w-56" />
27
+ <span className="flex items-center gap-2 rounded-md border px-3 py-2 text-sm">
28
+ <Icon className="size-4 text-muted-foreground" />
29
+ Painel comercial
30
+ </span>
31
+ </div>,
32
+ )
33
+ ```
34
+
35
+ ## Paleta própria
36
+
37
+ `icons` troca o vocabulário (nome → componente lucide). A paleta default é curta de propósito — cada ícone importado entra no bundle; monte a sua com o que faz sentido no domínio.
38
+
39
+ ```tsx preview col md
40
+ const [icon, setIcon] = useState('')
41
+
42
+ render(
43
+ <IconPicker
44
+ value={icon}
45
+ onChange={setIcon}
46
+ icons={{ 'zap': Zap, 'star': Star, 'flag': Flag, 'heart': Heart }}
47
+ placeholder="Selecione um ícone…"
48
+ className="w-56"
49
+ />,
50
+ )
51
+ ```
@@ -0,0 +1,78 @@
1
+ > Só um **ícone leading**? Não precisa do InputGroup — é a prop `icon` do `Input` (a mesma do Select e do Alert). O InputGroup é pros casos que a prop não cobre: botão no fim, prefixo de texto, adorno em bloco, múltiplos.
2
+
3
+ ## Com ícone (addon)
4
+
5
+ InputGroupAddon na borda (align inline-start por padrão) cola um ícone ao InputGroupInput dentro da mesma moldura. Clicar no addon foca o campo. Pra um leading simples, prefira `<Input icon={…} />`; aqui é quando o ícone convive com outros adornos.
6
+
7
+ ```tsx preview col
8
+ <InputGroup>
9
+ <InputGroupAddon>
10
+ <Search />
11
+ </InputGroupAddon>
12
+ <InputGroupInput placeholder="Buscar sessões do workspace" />
13
+ </InputGroup>
14
+ ```
15
+
16
+ ## Ícone + ação juntos (o caso do InputGroup)
17
+
18
+ > Só uma ação no fim (um limpar, um mostrar-senha)? Isso é `<Input trailing={…} />` — não precisa do InputGroup. O InputGroup entra quando os adornos se ACUMULAM: aqui, um ícone leading E um botão no fim, na mesma moldura (a busca do `ActionList` é assim). `align=inline-end` joga o addon pro fim; `InputGroupButton` já vem ghost, tamanho `icon-xs`.
19
+
20
+ ```tsx preview col
21
+ <InputGroup>
22
+ <InputGroupAddon>
23
+ <Search />
24
+ </InputGroupAddon>
25
+ <InputGroupInput placeholder="Buscar agente" defaultValue="reviewer" />
26
+ <InputGroupAddon align="inline-end">
27
+ <InputGroupButton size="icon-xs" aria-label="Limpar filtro">
28
+ <X />
29
+ </InputGroupButton>
30
+ </InputGroupAddon>
31
+ </InputGroup>
32
+ ```
33
+
34
+ ## Prefixo e sufixo
35
+
36
+ InputGroupText é o rótulo inerte na borda — prefixo ou sufixo. Aqui emoldura o slug do repositório entre o host fixo e o sufixo .git.
37
+
38
+ ```tsx preview col
39
+ <InputGroup>
40
+ <InputGroupAddon>
41
+ <GitBranch />
42
+ <InputGroupText>github.com/softize/</InputGroupText>
43
+ </InputGroupAddon>
44
+ <InputGroupInput placeholder="empresa-x-api" />
45
+ <InputGroupAddon align="inline-end">
46
+ <InputGroupText>.git</InputGroupText>
47
+ </InputGroupAddon>
48
+ </InputGroup>
49
+ ```
50
+
51
+ ## Composer com rodapé
52
+
53
+ Com InputGroupTextarea a moldura cresce; align=block-end empilha um rodapé de ações embaixo do campo — o padrão do composer de brief do agente.
54
+
55
+ ```tsx preview col
56
+ <InputGroup>
57
+ <InputGroupTextarea placeholder="Descreva a task para o agente developer" rows={3} />
58
+ <InputGroupAddon align="block-end">
59
+ <InputGroupText>
60
+ <Sparkles />
61
+ Título gerado pela IA
62
+ </InputGroupText>
63
+ <InputGroupButton size="sm" variant="default" className="ml-auto" aria-label="Enviar brief">
64
+ Enviar
65
+ <ArrowUp />
66
+ </InputGroupButton>
67
+ </InputGroupAddon>
68
+ </InputGroup>
69
+ ```
70
+
71
+ ## Props
72
+
73
+ | Prop | Tipo | Default | Descrição |
74
+ |---|---|---|---|
75
+ | `align` (InputGroupAddon) | `'inline-start' \| 'inline-end' \| 'block-start' \| 'block-end'` | `'inline-start'` | Onde o addon ancora: inline nas laterais; block empilha (vira coluna) acima ou abaixo — block exige a moldura alta de um InputGroupTextarea. |
76
+ | `size` (InputGroupButton) | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | Tamanho do botão embutido. As variantes icon-* são quadradas, pra um botão só de ícone. |
77
+ | `variant` (InputGroupButton) | `'default' \| 'secondary' \| 'outline' \| 'ghost' \| 'destructive' \| 'link'` | `'ghost'` | Intenção do botão (herda do Button). O padrão ghost some na moldura; use default pra a ação primária. |
78
+ | `placeholder / defaultValue / value` (InputGroupInput, InputGroupTextarea) | `string` | | Props nativas do <input>/<textarea> repassadas ao controle. Controle como faria com Input/Textarea (value + onChange). |
@@ -0,0 +1,72 @@
1
+ ## Básico
2
+
3
+ maxLength define quantas casas existem; cada InputOTPSlot recebe o index da sua posição. Um InputOTPGroup envolve as casas.
4
+
5
+ ```tsx preview
6
+ <InputOTP maxLength={6}>
7
+ <InputOTPGroup>
8
+ <InputOTPSlot index={0} />
9
+ <InputOTPSlot index={1} />
10
+ <InputOTPSlot index={2} />
11
+ <InputOTPSlot index={3} />
12
+ <InputOTPSlot index={4} />
13
+ <InputOTPSlot index={5} />
14
+ </InputOTPGroup>
15
+ </InputOTP>
16
+ ```
17
+
18
+ ## Com separador
19
+
20
+ Vários grupos com InputOTPSeparator entre eles quebram o código em blocos — os index seguem contínuos (0–5) por cima da divisão visual.
21
+
22
+ ```tsx preview
23
+ <InputOTP maxLength={6}>
24
+ <InputOTPGroup>
25
+ <InputOTPSlot index={0} />
26
+ <InputOTPSlot index={1} />
27
+ <InputOTPSlot index={2} />
28
+ </InputOTPGroup>
29
+ <InputOTPSeparator />
30
+ <InputOTPGroup>
31
+ <InputOTPSlot index={3} />
32
+ <InputOTPSlot index={4} />
33
+ <InputOTPSlot index={5} />
34
+ </InputOTPGroup>
35
+ </InputOTP>
36
+ ```
37
+
38
+ ## Controlado
39
+
40
+ value + onChange deixam o código no seu estado — bom pra liberar a ação só quando todas as casas estão preenchidas.
41
+
42
+ ```tsx preview col-start
43
+ const [code, setCode] = useState('')
44
+
45
+ render(
46
+ <>
47
+ <InputOTP maxLength={6} value={code} onChange={setCode}>
48
+ <InputOTPGroup>
49
+ <InputOTPSlot index={0} />
50
+ <InputOTPSlot index={1} />
51
+ <InputOTPSlot index={2} />
52
+ <InputOTPSlot index={3} />
53
+ <InputOTPSlot index={4} />
54
+ <InputOTPSlot index={5} />
55
+ </InputOTPGroup>
56
+ </InputOTP>
57
+ <p className="text-sm text-muted-foreground">
58
+ {code.length === 6 ? 'Código pronto pra confirmar o acesso ao workspace.' : 'Digite o código de 6 dígitos.'}
59
+ </p>
60
+ </>,
61
+ )
62
+ ```
63
+
64
+ ## Props
65
+
66
+ | Prop | Tipo | Default | Descrição |
67
+ |---|---|---|---|
68
+ | `maxLength` (InputOTP) | `number` | | Quantas casas o código tem — defina um InputOTPSlot por posição. |
69
+ | `value` (InputOTP) | `string` | | O código no modo controlado — parear com onChange. |
70
+ | `onChange` (InputOTP) | `(value: string) => void` | | Chamado a cada dígito; recebe o código acumulado. |
71
+ | `disabled` (InputOTP) | `boolean` | `false` | Esmaece e bloqueia a digitação do conjunto inteiro. |
72
+ | `index` (InputOTPSlot) | `number` | | A posição da casa (0-based); liga o slot ao dígito correspondente. |
@@ -0,0 +1,78 @@
1
+ ## Básico
2
+
3
+ Placeholder orienta o formato, não substitui o rótulo — em formulário de verdade, pareie com Label.
4
+
5
+ ```tsx preview col md
6
+ <Input placeholder="Ex.: empresa-x" />
7
+ ```
8
+
9
+ ## Ícone dentro do campo
10
+
11
+ `icon` põe um ícone LEADING dentro do campo — identidade (calendário na data, prédio na filial). É a MESMA prop do Select e do Alert: adorno de campo é **prop**, não composição à mão nem ícone jogado ao lado (que desalinha na quebra de linha e some no responsivo). Decorativo — quem nomeia é o Label.
12
+
13
+ ```tsx preview col md
14
+ <div className="grid gap-2">
15
+ <Label htmlFor="filial">Filial</Label>
16
+ <Input id="filial" icon={<Building2 />} placeholder="Ex.: Matriz" />
17
+ </div>
18
+ ```
19
+
20
+ Pra mais que um ícone — um botão no fim, um prefixo de texto, adorno em bloco — aí é `InputGroup` (a composição rica). Só o ícone leading é a prop.
21
+
22
+
23
+ ## Ação no fim do campo (trailing)
24
+
25
+ `trailing` é o par do `icon`: uma ação DENTRO do campo, no fim — um botão que age sobre o valor (limpar, mostrar senha). Igual ao Select. Diferente do ícone (decorativo), o trailing é interativo.
26
+
27
+ ```tsx preview col md
28
+ function Demo() {
29
+ const [q, setQ] = useState('preview pipeline')
30
+ return (
31
+ <Input
32
+ icon={<Search />}
33
+ value={q}
34
+ onChange={(e) => setQ(e.target.value)}
35
+ trailing={
36
+ q ? (
37
+ <Button variant="ghost" size="icon-xs" onClick={() => setQ('')}>
38
+ <X />
39
+ </Button>
40
+ ) : undefined
41
+ }
42
+ />
43
+ )
44
+ }
45
+ render(<Demo />)
46
+ ```
47
+
48
+ Pra MAIS de um adorno junto (ícone + botão + prefixo de texto), aí é `InputGroup`. Um ícone e/ou uma ação → props.
49
+
50
+ ## Com Label
51
+
52
+ htmlFor aponta pro id do campo — clicar no rótulo foca o input.
53
+
54
+ ```tsx preview col md
55
+ <div className="grid gap-2">
56
+ <Label htmlFor="client-name">Nome do cliente</Label>
57
+ <Input id="client-name" defaultValue="Empresa X" />
58
+ </div>
59
+ ```
60
+
61
+ ## Tipos nativos
62
+
63
+ type é o atributo nativo de <input> — teclado, máscara e validação vêm do browser de graça.
64
+
65
+ ```tsx preview col md
66
+ <Input type="email" placeholder="Ex.: joao@softize.com.br" />
67
+ <Input type="password" placeholder="Token de serviço" />
68
+ <Input type="number" placeholder="Porta do dev server" />
69
+ ```
70
+
71
+ ## Estados
72
+
73
+ Inválido é aria-invalid (borda e anel destructive) — semântica e visual na mesma prop, sem classe de erro à parte. disabled esmaece e bloqueia.
74
+
75
+ ```tsx preview col md
76
+ <Input aria-invalid defaultValue="empresa x" placeholder="Slug do workspace" />
77
+ <Input disabled defaultValue="softize-multica" />
78
+ ```
@@ -0,0 +1,84 @@
1
+ ## Básico
2
+
3
+ A composição completa: ItemMedia à esquerda, ItemContent (ItemTitle + ItemDescription) ocupando o meio e ItemActions à direita. variant=outline desenha a borda.
4
+
5
+ ```tsx preview col
6
+ <Item variant="outline">
7
+ <ItemMedia variant="icon">
8
+ <FolderGit2 />
9
+ </ItemMedia>
10
+ <ItemContent>
11
+ <ItemTitle>empresa-x-api</ItemTitle>
12
+ <ItemDescription>Repositório do backend do workspace Empresa X.</ItemDescription>
13
+ </ItemContent>
14
+ <ItemActions>
15
+ <Button size="sm" variant="outline">Abrir</Button>
16
+ </ItemActions>
17
+ </Item>
18
+ ```
19
+
20
+ ## Lista
21
+
22
+ Empilhe vários Item num ItemGroup e separe com ItemSeparator — o padrão pra listas de repositórios, agentes ou sessões.
23
+
24
+ ```tsx preview col
25
+ <ItemGroup>
26
+ <Item>
27
+ <ItemMedia variant="icon">
28
+ <GitBranch />
29
+ </ItemMedia>
30
+ <ItemContent>
31
+ <ItemTitle>empresa-x-web</ItemTitle>
32
+ <ItemDescription>Front do workspace Empresa X.</ItemDescription>
33
+ </ItemContent>
34
+ <ItemActions>
35
+ <Badge variant="success">sincronizado</Badge>
36
+ </ItemActions>
37
+ </Item>
38
+ <ItemSeparator />
39
+ <Item>
40
+ <ItemMedia variant="icon">
41
+ <GitBranch />
42
+ </ItemMedia>
43
+ <ItemContent>
44
+ <ItemTitle>empresa-x-api</ItemTitle>
45
+ <ItemDescription>Backend do workspace Empresa X.</ItemDescription>
46
+ </ItemContent>
47
+ <ItemActions>
48
+ <Badge variant="warning">3 sessões</Badge>
49
+ </ItemActions>
50
+ </Item>
51
+ </ItemGroup>
52
+ ```
53
+
54
+ ## Clicável e compacto
55
+
56
+ asChild funde o Item num <a> — a linha inteira vira alvo (hover no fundo). size=sm aperta o respiro; ItemMedia variant=image ancora um avatar.
57
+
58
+ ```tsx preview col
59
+ <Item asChild size="sm" variant="outline">
60
+ <a href="#empresa-x">
61
+ <ItemMedia>
62
+ <Avatar>
63
+ <AvatarFallback>AL</AvatarFallback>
64
+ </Avatar>
65
+ </ItemMedia>
66
+ <ItemContent>
67
+ <ItemTitle>Empresa X</ItemTitle>
68
+ <ItemDescription>Workspace com 2 repositórios e 3 agentes.</ItemDescription>
69
+ </ItemContent>
70
+ <ItemActions>
71
+ <ChevronRight className="size-4 text-muted-foreground" />
72
+ </ItemActions>
73
+ </a>
74
+ </Item>
75
+ ```
76
+
77
+ ## Props
78
+
79
+ | Prop | Tipo | Default | Descrição |
80
+ |---|---|---|---|
81
+ | `variant` (Item) | `'default' \| 'outline' \| 'muted'` | `'default'` | O fundo da linha — default transparente, outline com borda, muted levemente tingido. |
82
+ | `size` (Item) | `'default' \| 'sm'` | `'default'` | O respiro interno — sm aperta o padding pra listas densas. |
83
+ | `asChild` (Item) | `boolean` | `false` | Funde o Item no filho (ex.: <a> ou <button>) — a linha inteira vira o alvo. |
84
+ | `variant` (ItemMedia) | `'default' \| 'icon' \| 'image'` | `'default'` | A moldura da mídia — icon dá caixa quadrada com borda; image recorta a imagem; default sem moldura. |
@@ -0,0 +1,62 @@
1
+ ## Básico
2
+
3
+ Uma tecla por Kbd. É só visual — quem escuta o atalho é o seu handler, não o componente.
4
+
5
+ ```tsx preview
6
+ <Kbd>Esc</Kbd>
7
+ ```
8
+
9
+ ## Combinação
10
+
11
+ Envolva as teclas num KbdGroup e ponha o conector (+) como texto entre elas — o padrão pra paleta de comandos do Maestro.
12
+
13
+ ```tsx preview
14
+ <KbdGroup>
15
+ <Kbd>⌘</Kbd>
16
+ <span className="text-xs text-muted-foreground">+</span>
17
+ <Kbd>K</Kbd>
18
+ </KbdGroup>
19
+ ```
20
+
21
+ ## Com ícone
22
+
23
+ Um ícone (lucide) como filho do Kbd ganha size-3 automático — bom pra ⌘ e Enter, onde o glifo lê melhor que a letra.
24
+
25
+ ```tsx preview col-start
26
+ <KbdGroup>
27
+ <Kbd>
28
+ <Command />
29
+ </Kbd>
30
+ <Kbd>
31
+ <CornerDownLeft />
32
+ </Kbd>
33
+ </KbdGroup>
34
+ ```
35
+
36
+ ## No tooltip
37
+
38
+ Dentro de um TooltipContent o Kbd inverte o tom sozinho (fundo claro sobre o balão escuro) — anuncie o atalho da ação ao passar o mouse.
39
+
40
+ ```tsx preview
41
+ <Tooltip>
42
+ <TooltipTrigger className="text-sm text-muted-foreground underline underline-offset-4">
43
+ Abrir paleta de comandos
44
+ </TooltipTrigger>
45
+ <TooltipContent className="flex items-center gap-2">
46
+ Buscar workspace
47
+ <KbdGroup>
48
+ <Kbd>⌘</Kbd>
49
+ <Kbd>K</Kbd>
50
+ </KbdGroup>
51
+ </TooltipContent>
52
+ </Tooltip>
53
+ ```
54
+
55
+ ## Props
56
+
57
+ | Prop | Tipo | Default | Descrição |
58
+ |---|---|---|---|
59
+ | `children (Kbd)` | `React.ReactNode` | | A tecla — texto (Esc, ⌘, K) ou um ícone lucide, que recebe size-3 automático. |
60
+ | `className (Kbd)` | `string` | | Classes extras na tecla, mescladas com cn — pra ajustar tamanho ou cor pontualmente. |
61
+ | `children (KbdGroup)` | `React.ReactNode` | | As teclas do combo, mais o conector (ex.: "+") como texto entre elas. |
62
+ | `className (KbdGroup)` | `string` | | Classes extras no agrupador (inline-flex + gap-1), mescladas com cn. |
@@ -0,0 +1,32 @@
1
+ ## Com campo de texto
2
+
3
+ htmlFor aponta pro id do controle — clicar no rótulo foca o campo.
4
+
5
+ ```tsx preview col md
6
+ <div className="grid gap-2">
7
+ <Label htmlFor="workspace-name">Nome do workspace</Label>
8
+ <Input id="workspace-name" placeholder="Ex.: empresa-x" />
9
+ </div>
10
+ ```
11
+
12
+ ## Com Checkbox
13
+
14
+ O Label já é flex com gap — controle inline entra sem wrapper extra; clicar no texto alterna a caixa.
15
+
16
+ ```tsx preview
17
+ <div className="flex items-center gap-2">
18
+ <Checkbox id="notify-reviewer" defaultChecked />
19
+ <Label htmlFor="notify-reviewer">Avisar o revisor ao abrir o handoff</Label>
20
+ </div>
21
+ ```
22
+
23
+ ## Par desabilitado
24
+
25
+ Controle disabled esmaece o rótulo junto (peer-disabled) — o par inteiro comunica o estado, sem classe manual.
26
+
27
+ ```tsx preview
28
+ <div className="flex items-center gap-2">
29
+ <Checkbox id="archive-workspace" disabled />
30
+ <Label htmlFor="archive-workspace">Arquivar o workspace</Label>
31
+ </div>
32
+ ```
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Log
3
+ ---
4
+
5
+ # Log
6
+
7
+ Log estruturado que chega no handler já com contexto (per-request, per-action) via
8
+ `ctx.log`. O contrato é o `LoggerAdapter` — a mesma interface `Logger` que o core usa por
9
+ dentro, então o seu log e o do runtime saem no mesmo lugar, no mesmo formato.
10
+
11
+ ## O contrato
12
+
13
+ ```ts
14
+ interface Logger {
15
+ trace(msg: string, meta?: object): void
16
+ debug(msg: string, meta?: object): void
17
+ info(msg: string, meta?: object): void
18
+ warn(msg: string, meta?: object): void
19
+ error(msg: string, meta?: object): void
20
+ fatal(msg: string, meta?: object): void
21
+ child(bindings: object): Logger // logger derivado com bindings fixos
22
+ }
23
+ ```
24
+
25
+ ## Driver
26
+
27
+ ```ts
28
+ import pino from 'pino'
29
+ import { pinoLogger } from '@softize/opus/log/pino'
30
+
31
+ const logger = pinoLogger({ logger: pino({ level: 'info' }) })
32
+ ```
33
+
34
+ O `pino` é seu (nível, transport, redact) — o driver só faz a ponte. Peer opcional: quem
35
+ não usa o driver não instala o `pino`.
36
+
37
+ ## No runtime
38
+
39
+ ```ts
40
+ const runtime = createRuntime({
41
+ // …server/data…
42
+ logger,
43
+ })
44
+
45
+ // No handler: ctx.log já vem com o requestId/action injetados (via child()).
46
+ handler: async (ctx, input) => {
47
+ ctx.log.info('emitindo nota', { valor: input.valor })
48
+ return repo.create(input)
49
+ }
50
+ ```
51
+
52
+ ## Limites (por enquanto)
53
+
54
+ Superfície mínima de níveis + `child`. Sem sampling nem transports próprios — isso mora no
55
+ `pino` que você passa. Drivers hoje: `pino`; outros entram por reincidência.
@@ -0,0 +1,41 @@
1
+ ## Fonte e resultado
2
+
3
+ Uso: <Markdown content={fonte} />. No palco, o resultado; no bloco abaixo, a fonte markdown que o produziu. O componente recebe só content: string.
4
+
5
+ ```tsx preview col 2xl
6
+ const sample = [
7
+ '# Markdown na Softize',
8
+ '',
9
+ 'Renderiza **doc técnica** e mensagem de chat — `SKILL.md`, síntese de papel, resposta de agente.',
10
+ 'O motor é o markdown-it, o MESMO que renderiza estas páginas.',
11
+ '',
12
+ '## Sintaxe coberta',
13
+ '',
14
+ '- Headings de `#` a `####`',
15
+ '- Listas com `-` ou numeradas',
16
+ '- **Negrito**, código inline e [links](https://softize.com.br)',
17
+ '',
18
+ '1. Primeiro passo',
19
+ '2. Segundo passo',
20
+ '',
21
+ '> Citação calma, pro tom certo.',
22
+ '',
23
+ '---',
24
+ '',
25
+ '```ts',
26
+ 'function ola(): string {',
27
+ " return 'mundo'",
28
+ '}',
29
+ '```',
30
+ ].join('\n')
31
+
32
+ render(<Markdown content={sample} />)
33
+ ```
34
+
35
+
36
+ ## Props
37
+
38
+ | Prop | Tipo | Default | Descrição |
39
+ |---|---|---|---|
40
+ | `content` | `string` | | O markdown cru (CommonMark + tabela GFM, via markdown-it). HTML no fonte é **escapado**, não interpretado — por isso serve pra texto vindo de gente ou de modelo. |
41
+ | `className` | `string` | | Classes do wrapper. |