@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,69 @@
1
+ ## Básico
2
+
3
+ Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a chave. defaultChecked pro modo não controlado.
4
+
5
+ ```tsx preview
6
+ <div className="flex items-center gap-2">
7
+ <Switch id="boot-preview" defaultChecked />
8
+ <Label htmlFor="boot-preview">Subir o preview ao abrir a sessão</Label>
9
+ </div>
10
+ ```
11
+
12
+ ## Controlado
13
+
14
+ onCheckedChange recebe um boolean — pareie com checked pra guardar o estado no componente que decide.
15
+
16
+ ```tsx preview
17
+ const [autoReview, setAutoReview] = useState(true)
18
+
19
+ render(
20
+ <div className="flex items-center gap-2">
21
+ <Switch
22
+ id="auto-review"
23
+ checked={autoReview}
24
+ onCheckedChange={setAutoReview}
25
+ />
26
+ <Label htmlFor="auto-review">Acionar o revisor ao abrir o handoff</Label>
27
+ </div>,
28
+ )
29
+ ```
30
+
31
+ ## Tamanho sm
32
+
33
+ size=sm encolhe a chave — pra densidade em linha de lista, como cada repositório do workspace.
34
+
35
+ ```tsx preview col-start
36
+ <div className="flex items-center gap-2">
37
+ <Switch id="sync-empresa-x-api" size="sm" defaultChecked />
38
+ <Label htmlFor="sync-empresa-x-api">empresa-x-api</Label>
39
+ </div>
40
+ <div className="flex items-center gap-2">
41
+ <Switch id="sync-empresa-x-web" size="sm" />
42
+ <Label htmlFor="sync-empresa-x-web">empresa-x-web</Label>
43
+ </div>
44
+ ```
45
+
46
+ ## Desabilitado
47
+
48
+ disabled esmaece e bloqueia a chave — ligada ou desligada — e o rótulo em par esmaece junto (peer-disabled).
49
+
50
+ ```tsx preview col-start
51
+ <div className="flex items-center gap-2">
52
+ <Switch id="sync-multica" disabled />
53
+ <Label htmlFor="sync-multica">Sincronizar com o Multica</Label>
54
+ </div>
55
+ <div className="flex items-center gap-2">
56
+ <Switch id="opus" disabled defaultChecked />
57
+ <Label htmlFor="opus">Opus inicializado</Label>
58
+ </div>
59
+ ```
60
+
61
+ ## Props
62
+
63
+ | Prop | Tipo | Default | Descrição |
64
+ |---|---|---|---|
65
+ | `checked` | `boolean` | | O estado, no modo controlado — parear com onCheckedChange. |
66
+ | `onCheckedChange` | `(checked: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
67
+ | `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
68
+ | `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave — sm pra densidade em linha de lista. |
69
+ | `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
@@ -0,0 +1,102 @@
1
+ ## Tabela de domínio
2
+
3
+ A Table vem SEM borda externa — só as divisórias de linha (a última o TableBody zera). Coluna numérica alinha à direita (text-right no TableHead E no TableCell). A TableCaption fica embaixo (caption-bottom) e descreve a tabela.
4
+
5
+ ```tsx preview col
6
+ <Table>
7
+ <TableCaption>Sessões recentes do workspace Empresa X.</TableCaption>
8
+ <TableHeader>
9
+ <TableRow>
10
+ <TableHead>Sessão</TableHead>
11
+ <TableHead>Agente</TableHead>
12
+ <TableHead>Status</TableHead>
13
+ <TableHead className="text-right">Duração</TableHead>
14
+ </TableRow>
15
+ </TableHeader>
16
+ <TableBody>
17
+ <TableRow>
18
+ <TableCell className="font-medium">Importar pedidos da transportadora</TableCell>
19
+ <TableCell>developer</TableCell>
20
+ <TableCell><Badge variant="info">Em sessão</Badge></TableCell>
21
+ <TableCell className="text-right">42 min</TableCell>
22
+ </TableRow>
23
+ <TableRow>
24
+ <TableCell className="font-medium">Revisar contrato de rastreio</TableCell>
25
+ <TableCell>reviewer</TableCell>
26
+ <TableCell><Badge variant="warning">Aguardando revisor</Badge></TableCell>
27
+ <TableCell className="text-right">18 min</TableCell>
28
+ </TableRow>
29
+ <TableRow>
30
+ <TableCell className="font-medium">Ajustar microcopy do painel</TableCell>
31
+ <TableCell>designer</TableCell>
32
+ <TableCell><Badge variant="success">Concluída</Badge></TableCell>
33
+ <TableCell className="text-right">7 min</TableCell>
34
+ </TableRow>
35
+ </TableBody>
36
+ </Table>
37
+ ```
38
+
39
+ ## Moldura (o datagrid da casa)
40
+
41
+ A borda externa NÃO é do componente: é um wrapper `overflow-hidden rounded-lg border border-border` por fora — o estilo padrão de datagrid do back-office. O `overflow-hidden` recorta os cantos e contém o scroll horizontal; a última linha já vem sem divisória, então o quadro fecha limpo. O ActionList aplica a moldura sozinho na tabela derivada; em tabela montada à mão, é você quem embrulha.
42
+
43
+ ```tsx preview col
44
+ <div className="w-full overflow-hidden rounded-lg border border-border">
45
+ <Table>
46
+ <TableHeader>
47
+ <TableRow>
48
+ <TableHead>Sessão</TableHead>
49
+ <TableHead>Agente</TableHead>
50
+ <TableHead className="text-right">Duração</TableHead>
51
+ </TableRow>
52
+ </TableHeader>
53
+ <TableBody>
54
+ <TableRow>
55
+ <TableCell className="font-medium">Importar pedidos da transportadora</TableCell>
56
+ <TableCell>developer</TableCell>
57
+ <TableCell className="text-right">42 min</TableCell>
58
+ </TableRow>
59
+ <TableRow>
60
+ <TableCell className="font-medium">Revisar contrato de rastreio</TableCell>
61
+ <TableCell>reviewer</TableCell>
62
+ <TableCell className="text-right">18 min</TableCell>
63
+ </TableRow>
64
+ </TableBody>
65
+ </Table>
66
+ </div>
67
+ ```
68
+
69
+ ## Com rodapé (TableFooter)
70
+
71
+ TableFooter fecha a tabela com a linha de agregação — fundo muted e peso de fonte já vêm prontos.
72
+
73
+ ```tsx preview col
74
+ <Table>
75
+ <TableHeader>
76
+ <TableRow>
77
+ <TableHead>Agente</TableHead>
78
+ <TableHead className="text-right">Skills vinculadas</TableHead>
79
+ </TableRow>
80
+ </TableHeader>
81
+ <TableBody>
82
+ <TableRow>
83
+ <TableCell className="font-medium">developer</TableCell>
84
+ <TableCell className="text-right">6</TableCell>
85
+ </TableRow>
86
+ <TableRow>
87
+ <TableCell className="font-medium">reviewer</TableCell>
88
+ <TableCell className="text-right">4</TableCell>
89
+ </TableRow>
90
+ <TableRow>
91
+ <TableCell className="font-medium">designer</TableCell>
92
+ <TableCell className="text-right">3</TableCell>
93
+ </TableRow>
94
+ </TableBody>
95
+ <TableFooter>
96
+ <TableRow>
97
+ <TableCell>Total</TableCell>
98
+ <TableCell className="text-right">13</TableCell>
99
+ </TableRow>
100
+ </TableFooter>
101
+ </Table>
102
+ ```
@@ -0,0 +1,94 @@
1
+ ## Padrão (pill)
2
+
3
+ O value do TabsTrigger pareia com o do TabsContent. defaultValue deixa o estado com o componente; pra controlar, use value + onValueChange.
4
+
5
+ ```tsx preview col
6
+ <Tabs defaultValue="sessions">
7
+ <TabsList>
8
+ <TabsTrigger value="overview">Visão geral</TabsTrigger>
9
+ <TabsTrigger value="sessions">Sessões</TabsTrigger>
10
+ <TabsTrigger value="skills">Skills</TabsTrigger>
11
+ </TabsList>
12
+ <TabsContent value="overview">
13
+ <p className="text-sm text-muted-foreground">Resumo do workspace Empresa X.</p>
14
+ </TabsContent>
15
+ <TabsContent value="sessions">
16
+ <p className="text-sm text-muted-foreground">3 sessões nesta semana, 1 em andamento.</p>
17
+ </TabsContent>
18
+ <TabsContent value="skills">
19
+ <p className="text-sm text-muted-foreground">6 skills vinculadas aos agentes do workspace.</p>
20
+ </TabsContent>
21
+ </Tabs>
22
+ ```
23
+
24
+ ## Variante line
25
+
26
+ variant=line na TabsList: fundo transparente, o ativo é marcado pelo traço embaixo — bom pra cabeçalho de página, onde o pill pesaria.
27
+
28
+ ```tsx preview col
29
+ <Tabs defaultValue="agents">
30
+ <TabsList variant="line">
31
+ <TabsTrigger value="agents">Agentes</TabsTrigger>
32
+ <TabsTrigger value="repos">Repositórios</TabsTrigger>
33
+ <TabsTrigger value="settings">Configurações</TabsTrigger>
34
+ </TabsList>
35
+ <TabsContent value="agents">
36
+ <p className="text-sm text-muted-foreground">developer, reviewer e designer ativos.</p>
37
+ </TabsContent>
38
+ <TabsContent value="repos">
39
+ <p className="text-sm text-muted-foreground">empresa-x-api e empresa-x-web vinculados.</p>
40
+ </TabsContent>
41
+ <TabsContent value="settings">
42
+ <p className="text-sm text-muted-foreground">Preferências do workspace.</p>
43
+ </TabsContent>
44
+ </Tabs>
45
+ ```
46
+
47
+ ## Vertical
48
+
49
+ orientation=vertical no Tabs: a lista vira coluna e o traço da variante line migra pra lateral direita do trigger.
50
+
51
+ ```tsx preview col
52
+ <Tabs defaultValue="prompt" orientation="vertical">
53
+ <TabsList>
54
+ <TabsTrigger value="prompt">Prompt</TabsTrigger>
55
+ <TabsTrigger value="skills">Skills</TabsTrigger>
56
+ <TabsTrigger value="history">Histórico</TabsTrigger>
57
+ </TabsList>
58
+ <TabsContent value="prompt">
59
+ <p className="text-sm text-muted-foreground">O prompt do agente developer.</p>
60
+ </TabsContent>
61
+ <TabsContent value="skills">
62
+ <p className="text-sm text-muted-foreground">Skills vinculadas a este agente.</p>
63
+ </TabsContent>
64
+ <TabsContent value="history">
65
+ <p className="text-sm text-muted-foreground">Sessões anteriores deste agente.</p>
66
+ </TabsContent>
67
+ </Tabs>
68
+ ```
69
+
70
+ ## Densidade (size)
71
+
72
+ `size="sm"` no `Tabs` baixa a lista de h-9 (36px) pra h-8 (32px) — o par do `sm` que Button e Select já têm, pra uma fileira densa (toolbar, header) onde o segmento não pode ficar mais alto que os irmãos.
73
+
74
+ ```tsx preview col
75
+ <Tabs defaultValue="preview" size="sm">
76
+ <TabsList>
77
+ <TabsTrigger value="preview" className="text-xs">Preview</TabsTrigger>
78
+ <TabsTrigger value="code" className="text-xs">Código</TabsTrigger>
79
+ <TabsTrigger value="ai" className="text-xs">IA</TabsTrigger>
80
+ </TabsList>
81
+ </Tabs>
82
+ ```
83
+
84
+ ## Props
85
+
86
+ | Prop | Tipo | Default | Descrição |
87
+ |---|---|---|---|
88
+ | `defaultValue (Tabs)` | `string` | | A aba inicial no modo não-controlado. |
89
+ | `value (Tabs)` | `string` | | A aba ativa no modo controlado — pareie com onValueChange. |
90
+ | `onValueChange (Tabs)` | `(value: string) => void` | | Chamado quando o usuário troca de aba. |
91
+ | `size (Tabs)` | `'default' \| 'sm'` | `'default'` | Altura da lista: default (h-9) ou sm (h-8), o par do sm de Button/Select. Flui pra TabsList por contexto. |
92
+ | `orientation (Tabs)` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas — vertical vira coluna lateral. |
93
+ | `variant (TabsList)` | `'default' \| 'line'` | `'default'` | default é o pill (fundo muted); line é a barra sublinhada, sem fundo. |
94
+ | `value (TabsTrigger/TabsContent)` | `string` | | Identificador que pareia o trigger com o painel correspondente. |
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: Testes de action
3
+ ---
4
+
5
+ # Testes de action
6
+
7
+ A unidade natural de teste no Opus é a **action** — o contrato: input → output/erro,
8
+ bordas do schema, autorização fail-closed. `@softize/opus/testing` roda esse contrato
9
+ em unidade, sem montar runtime nem mockar contexto à mão.
10
+
11
+ ## runAction — o contrato em unidade
12
+
13
+ O harness executa o **mesmo pipeline do runtime**: valida o input → cobra o gate
14
+ `public` → avalia o `authorize` (string DSL ou closure, semântica idêntica) → roda o
15
+ handler → valida o output. Falha estoura o mesmo `ActionError` tipado do runtime
16
+ (`validation.invalid_input`, `auth.unauthenticated`, `auth.forbidden`…).
17
+
18
+ ```ts
19
+ import { runAction } from '@softize/opus/testing'
20
+ import { taskList } from './list.ts'
21
+
22
+ it('lista as fixtures com o shape do contrato', async () => {
23
+ const { output } = await runAction(taskList, {}, { user: { id: 'u1' } })
24
+ expect(output.total).toBe(2)
25
+ })
26
+
27
+ it('sem usuário, barra: a action não é pública', async () => {
28
+ await expect(runAction(taskList, {})).rejects.toMatchObject({ code: 'auth.unauthenticated' })
29
+ })
30
+ ```
31
+
32
+ O terceiro argumento configura o contexto e substitui os loaders (que não rodam em
33
+ unidade): `{ user, tenantId, can, db, storage, ai, loaded, meta }`. O `authorize` vê
34
+ o `loaded` como no runtime:
35
+
36
+ ```ts
37
+ it('só a dona edita', async () => {
38
+ const opts = { loaded: { task: { ownerId: 'u1' } } }
39
+ await runAction(taskUpdate, { id: '1' }, { ...opts, user: { id: 'u1' } }) // passa
40
+ await expect(
41
+ runAction(taskUpdate, { id: '1' }, { ...opts, user: { id: 'u2' } }),
42
+ ).rejects.toMatchObject({ code: 'auth.forbidden' })
43
+ })
44
+ ```
45
+
46
+ ## Contexto observável
47
+
48
+ `runAction` (e `testContext`, pra quem quer só o ctx) devolve os efeitos capturados —
49
+ o teste afirma o que importa:
50
+
51
+ ```ts
52
+ const { output, emitted, logged } = await runAction(taskDone, { id: '1' }, { user })
53
+ expect(emitted).toEqual([{ event: 'task.done', data: { id: '1' } }])
54
+ ```
55
+
56
+ ## memStorage
57
+
58
+ `StorageAdapter` em memória com a mesma régua de key dos drivers reais — pra handler
59
+ que anexa arquivo:
60
+
61
+ ```ts
62
+ import { memStorage, runAction } from '@softize/opus/testing'
63
+
64
+ const storage = memStorage()
65
+ await runAction(notaAnexar, { id: '9' }, { user, storage })
66
+ expect(storage.keys()).toEqual(['notas/9.pdf'])
67
+ ```
68
+
69
+ ## fake — fixtures do schema
70
+
71
+ `fake(schema)` / `fakeMany(schema, n)` geram dado sintético **determinístico** que satisfaz o
72
+ schema zod — matéria-prima do `mockHandler` (modo design) e de fixtures de teste. Semeado
73
+ (mesma `seed` → mesma saída, sem `Math.random`), com heurística por check do zod (email, uuid,
74
+ url, datetime) e por nome de campo (email, id, `*At`→data, telefone, cpf/cnpj, nome…), sabor pt-BR.
75
+
76
+ ```ts
77
+ import { fake, fakeMany } from '@softize/opus/testing'
78
+
79
+ const one = fake(EventEntity.zod()) // 1 evento válido (safeParse passa)
80
+ const many = fakeMany(EventEntity.zod(), 20) // 20, estáveis entre execuções
81
+ fake(schema, { seed: 7 }) // seed própria
82
+ ```
83
+
84
+ ## O que fica de fora
85
+
86
+ De propósito — é harness de **unidade**: loaders reais (passe `loaded` pronto), audit,
87
+ reactions em cadeia e o servidor. Fluxo completo é teste de integração com o runtime.
88
+ `requires` é declarativo no protocolo (o runtime não o executa) — no harness idem;
89
+ handler que chama `ctx.can` responde ao `can` das options.
@@ -0,0 +1,30 @@
1
+ ## Básico
2
+
3
+ Cresce com o conteúdo a partir da altura mínima (field-sizing-content) — digite e veja.
4
+
5
+ ```tsx preview col md
6
+ <Textarea placeholder="Descreva o que o agente deve fazer nesta sessão." />
7
+ ```
8
+
9
+ ## Com Label
10
+
11
+ O mesmo par htmlFor↔id dos outros campos — o overview do handoff é o caso típico.
12
+
13
+ ```tsx preview col md
14
+ <div className="grid gap-2">
15
+ <Label htmlFor="overview">Overview da task</Label>
16
+ <Textarea
17
+ id="overview"
18
+ defaultValue="Ajustar a microcopy do handoff: frases com maiúscula e ponto, labels curtos sem ponto."
19
+ />
20
+ </div>
21
+ ```
22
+
23
+ ## Estados
24
+
25
+ aria-invalid pinta borda e anel destructive; disabled esmaece e bloqueia a edição.
26
+
27
+ ```tsx preview col md
28
+ <Textarea aria-invalid placeholder="Conte o contexto da mudança." />
29
+ <Textarea disabled defaultValue="Sessão encerrada — o brief não pode mais ser editado." />
30
+ ```
@@ -0,0 +1,67 @@
1
+ ## Tipos
2
+
3
+ Cada tipo já vem com o ícone lucide do Opus. O título é label (sem ponto); a description, frase (com ponto).
4
+
5
+ ```tsx preview
6
+ <Button variant="outline" onClick={() => toast.success('Workspace criado')}>Sucesso</Button>
7
+ <Button
8
+ variant="outline"
9
+ onClick={() => toast.error('Falha no push', { description: 'O Multica não respondeu — tente de novo.' })}
10
+ >
11
+ Erro
12
+ </Button>
13
+ <Button variant="outline" onClick={() => toast.info('Base atualizada')}>Info</Button>
14
+ <Button
15
+ variant="outline"
16
+ onClick={() => toast.warning('Preview parado', { description: 'Inicie o ambiente pra ver a sessão.' })}
17
+ >
18
+ Aviso
19
+ </Button>
20
+ ```
21
+
22
+ ## Ação e progresso
23
+
24
+ action põe um botão no toast (ex.: desfazer); toast.promise acompanha uma operação — loading vira sucesso ou erro sozinho.
25
+
26
+ ```tsx preview
27
+ <Button
28
+ variant="outline"
29
+ onClick={() =>
30
+ toast('Sessão arquivada', {
31
+ action: { label: 'Desfazer', onClick: () => toast.success('Sessão restaurada') },
32
+ })
33
+ }
34
+ >
35
+ Com ação
36
+ </Button>
37
+ <Button
38
+ variant="outline"
39
+ onClick={() =>
40
+ toast.promise(new Promise((resolve) => setTimeout(resolve, 1800)), {
41
+ loading: 'Publicando no Multica…',
42
+ success: 'Agentes publicados',
43
+ error: 'Falha ao publicar',
44
+ })
45
+ }
46
+ >
47
+ Promise
48
+ </Button>
49
+ ```
50
+
51
+ ## Toaster no root
52
+
53
+ Monte uma vez, fora do App. Divergência declarada: sem next-themes — o tema vem por prop (default 'system'); a elevação dark usa bg-popover.
54
+
55
+ ```tsx
56
+ /* main.tsx do app — uma vez. */
57
+ <App />
58
+ <Toaster />
59
+ ```
60
+
61
+ ## Props
62
+
63
+ | Prop | Tipo | Default | Descrição |
64
+ |---|---|---|---|
65
+ | `Toaster.theme` | `'light' \| 'dark' \| 'system'` | `'system'` | Força o tema dos toasts — sem next-themes, a escolha é do app. |
66
+ | `Toaster.position` | `'bottom-right' \| 'top-center' \| …` | `'bottom-right'` | Canto onde os toasts aparecem (sonner). |
67
+ | `toast(title, opts)` | `{ description?, action?, duration?, … }` | | A API de disparo (sonner): descrição, botão de ação e duração por toast. |
@@ -0,0 +1,81 @@
1
+ ## Escolha única
2
+
3
+ type=single deixa um item ativo por vez; value é uma string. Controlado por value + onValueChange — bom pra alternar a visão de um workspace.
4
+
5
+ ```tsx preview
6
+ const [view, setView] = useState('sessions')
7
+
8
+ render(
9
+ <ToggleGroup type="single" value={view} onValueChange={(v) => v && setView(v)}>
10
+ <ToggleGroupItem value="overview">Visão geral</ToggleGroupItem>
11
+ <ToggleGroupItem value="sessions">Sessões</ToggleGroupItem>
12
+ <ToggleGroupItem value="skills">Skills</ToggleGroupItem>
13
+ </ToggleGroup>,
14
+ )
15
+ ```
16
+
17
+ ## Escolha múltipla
18
+
19
+ type=multiple permite vários ativos ao mesmo tempo; value é um array de strings. O padrão pra uma barra de formatação.
20
+
21
+ ```tsx preview
22
+ const [marks, setMarks] = useState(['bold'])
23
+
24
+ render(
25
+ <ToggleGroup type="multiple" value={marks} onValueChange={setMarks}>
26
+ <ToggleGroupItem value="bold" aria-label="Negrito">
27
+ <Bold />
28
+ </ToggleGroupItem>
29
+ <ToggleGroupItem value="italic" aria-label="Itálico">
30
+ <Italic />
31
+ </ToggleGroupItem>
32
+ <ToggleGroupItem value="underline" aria-label="Sublinhado">
33
+ <Underline />
34
+ </ToggleGroupItem>
35
+ </ToggleGroup>,
36
+ )
37
+ ```
38
+
39
+ ## Variante outline
40
+
41
+ variant=outline emoldura o grupo com borda; size e o variant definidos no ToggleGroup descem pra cada ToggleGroupItem via contexto.
42
+
43
+ ```tsx preview
44
+ <ToggleGroup type="single" variant="outline" defaultValue="left" aria-label="Alinhamento">
45
+ <ToggleGroupItem value="left" aria-label="Esquerda">
46
+ <AlignLeft />
47
+ </ToggleGroupItem>
48
+ <ToggleGroupItem value="center" aria-label="Centro">
49
+ <AlignCenter />
50
+ </ToggleGroupItem>
51
+ <ToggleGroupItem value="right" aria-label="Direita">
52
+ <AlignRight />
53
+ </ToggleGroupItem>
54
+ </ToggleGroup>
55
+ ```
56
+
57
+ ## Com espaçamento
58
+
59
+ spacing afasta os itens (em unidades de spacing do tema) — sem ele os botões ficam colados num bloco único.
60
+
61
+ ```tsx preview
62
+ <ToggleGroup type="single" variant="outline" spacing={2} defaultValue="developer">
63
+ <ToggleGroupItem value="developer">developer</ToggleGroupItem>
64
+ <ToggleGroupItem value="reviewer">reviewer</ToggleGroupItem>
65
+ <ToggleGroupItem value="designer">designer</ToggleGroupItem>
66
+ </ToggleGroup>
67
+ ```
68
+
69
+ ## Props
70
+
71
+ | Prop | Tipo | Default | Descrição |
72
+ |---|---|---|---|
73
+ | `type (ToggleGroup)` | `'single' \| 'multiple'` | | single mantém um item ativo (value: string); multiple permite vários (value: string[]). |
74
+ | `value (ToggleGroup)` | `string \| string[]` | | O(s) item(ns) ativo(s) no modo controlado — pareie com onValueChange. O tipo segue o type. |
75
+ | `onValueChange (ToggleGroup)` | `(value: string \| string[]) => void` | | Chamado quando a seleção muda. No single, vem string vazia ao desmarcar o ativo. |
76
+ | `defaultValue (ToggleGroup)` | `string \| string[]` | | A seleção inicial no modo não controlado. |
77
+ | `variant (ToggleGroup)` | `'default' \| 'outline'` | `'default'` | default é sem moldura; outline emoldura o grupo com borda. Desce pros itens via contexto. |
78
+ | `size (ToggleGroup)` | `'default' \| 'sm' \| 'lg'` | `'default'` | Altura e respiro dos itens. Desce pros itens via contexto. |
79
+ | `spacing (ToggleGroup)` | `number` | `0` | Distância entre os itens (unidades de spacing). 0 cola tudo num bloco único. |
80
+ | `value (ToggleGroupItem)` | `string` | | Identificador do item — é o que entra no value do grupo quando ativado. |
81
+ | `disabled (ToggleGroupItem)` | `boolean` | `false` | Esmaece e bloqueia um item específico do grupo. |
@@ -0,0 +1,72 @@
1
+ ## Básico
2
+
3
+ Um botão que lembra se está ligado. defaultPressed deixa o estado com o componente; o filho costuma ser um ícone.
4
+
5
+ ```tsx preview
6
+ <Toggle defaultPressed aria-label="Negrito">
7
+ <Bold />
8
+ </Toggle>
9
+ ```
10
+
11
+ ## Controlado
12
+
13
+ pressed + onPressedChange tiram o estado do componente — o booleano fica no seu store. Bom pra alternar o modo somente-leitura de uma sessão.
14
+
15
+ ```tsx preview
16
+ const [readOnly, setReadOnly] = useState(true)
17
+
18
+ render(
19
+ <Toggle
20
+ variant="outline"
21
+ pressed={readOnly}
22
+ onPressedChange={setReadOnly}
23
+ >
24
+ <Eye />
25
+ Somente leitura
26
+ </Toggle>,
27
+ )
28
+ ```
29
+
30
+ ## Variantes e tamanhos
31
+
32
+ variant default não tem borda (o fundo só aparece ativo); outline carrega a borda. size sm/default/lg ajusta a altura.
33
+
34
+ ```tsx preview
35
+ <Toggle aria-label="Quebra de linha">
36
+ <WrapText />
37
+ </Toggle>
38
+ <Toggle variant="outline" aria-label="Quebra de linha">
39
+ <WrapText />
40
+ </Toggle>
41
+ <Toggle variant="outline" size="sm" defaultPressed>
42
+ Compacto
43
+ </Toggle>
44
+ <Toggle variant="outline" size="lg" defaultPressed>
45
+ Confortável
46
+ </Toggle>
47
+ ```
48
+
49
+ ## Desabilitado
50
+
51
+ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
52
+
53
+ ```tsx preview
54
+ <Toggle disabled aria-label="Negrito">
55
+ <Bold />
56
+ </Toggle>
57
+ <Toggle disabled defaultPressed variant="outline">
58
+ <Eye />
59
+ Somente leitura
60
+ </Toggle>
61
+ ```
62
+
63
+ ## Props
64
+
65
+ | Prop | Tipo | Default | Descrição |
66
+ |---|---|---|---|
67
+ | `pressed` | `boolean` | | O estado ligado/desligado no modo controlado — parear com onPressedChange. |
68
+ | `onPressedChange` | `(pressed: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
69
+ | `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
70
+ | `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
71
+ | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm pra toolbar densa, lg pra alvo mais confortável. |
72
+ | `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |