@omnizap-system/omnizap 2.6.0 → 2.6.2

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 (261) hide show
  1. package/.env.example +58 -13
  2. package/.github/workflows/ci.yml +5 -5
  3. package/.github/workflows/codeql.yml +1 -1
  4. package/.github/workflows/db-migration-check.yml +2 -2
  5. package/.github/workflows/dependency-review.yml +1 -1
  6. package/.github/workflows/deploy.yml +2 -2
  7. package/.github/workflows/release.yml +2 -2
  8. package/.github/workflows/security-attest-provenance.yml +2 -2
  9. package/.github/workflows/security-gitleaks.yml +13 -4
  10. package/.github/workflows/security-runner-hardening.yml +2 -2
  11. package/.github/workflows/security-scorecard.yml +1 -1
  12. package/.github/workflows/security-zap-baseline.yml +1 -1
  13. package/.github/workflows/security-zap-full-scan.yml +2 -1
  14. package/.github/workflows/security-zizmor.yml +1 -1
  15. package/.github/workflows/wiki-sync.yml +1 -1
  16. package/.gitleaksignore +9 -0
  17. package/CODE_OF_CONDUCT.md +2 -2
  18. package/GEMINI.md +64 -0
  19. package/README.md +52 -82
  20. package/SECURITY.md +1 -1
  21. package/app/config/index.js +2 -0
  22. package/app/configParts/adminIdentity.js +5 -5
  23. package/app/configParts/baileysConfig.js +230 -58
  24. package/app/configParts/groupUtils.js +5 -0
  25. package/app/configParts/messagePersistenceService.js +145 -4
  26. package/app/configParts/sessionConfig.js +157 -0
  27. package/app/connection/baileysCompatibility.test.js +1 -1
  28. package/app/connection/groupOwnerWriteStateResolver.js +109 -0
  29. package/app/connection/socketController.js +660 -158
  30. package/app/connection/socketController.multiSession.test.js +108 -0
  31. package/app/controllers/messageController.js +1 -1
  32. package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
  33. package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
  34. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
  35. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
  36. package/app/controllers/messageProcessingPipeline.js +93 -13
  37. package/app/controllers/messageProcessingPipeline.test.js +200 -0
  38. package/app/modules/adminModule/AGENT.md +1 -1
  39. package/app/modules/adminModule/commandConfig.json +3318 -1347
  40. package/app/modules/adminModule/groupCommandHandlers.js +858 -15
  41. package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
  42. package/app/modules/adminModule/groupWarningRepository.js +152 -0
  43. package/app/modules/aiModule/AGENT.md +47 -30
  44. package/app/modules/aiModule/aiConfigRuntime.js +1 -0
  45. package/app/modules/aiModule/catCommand.js +135 -27
  46. package/app/modules/aiModule/commandConfig.json +114 -28
  47. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
  48. package/app/modules/gameModule/AGENT.md +1 -1
  49. package/app/modules/gameModule/commandConfig.json +29 -0
  50. package/app/modules/menuModule/AGENT.md +1 -1
  51. package/app/modules/menuModule/commandConfig.json +45 -10
  52. package/app/modules/menuModule/menuCatalogService.js +190 -0
  53. package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
  54. package/app/modules/menuModule/menuDynamicService.js +511 -0
  55. package/app/modules/menuModule/menuDynamicService.test.js +141 -0
  56. package/app/modules/menuModule/menus.js +36 -5
  57. package/app/modules/playModule/AGENT.md +10 -5
  58. package/app/modules/playModule/commandConfig.json +140 -12
  59. package/app/modules/playModule/playCommand.js +1 -1417
  60. package/app/modules/playModule/playCommandConstants.js +80 -0
  61. package/app/modules/playModule/playCommandCore.js +361 -0
  62. package/app/modules/playModule/playCommandHandlers.js +41 -0
  63. package/app/modules/playModule/playCommandMediaClient.js +1872 -0
  64. package/app/modules/playModule/playConfigRuntime.js +245 -4
  65. package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
  66. package/app/modules/quoteModule/AGENT.md +1 -1
  67. package/app/modules/quoteModule/commandConfig.json +29 -0
  68. package/app/modules/quoteModule/quoteCommand.js +3 -2
  69. package/app/modules/rpgPokemonModule/AGENT.md +1 -1
  70. package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
  71. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
  72. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
  73. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
  74. package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
  75. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
  76. package/app/modules/statsModule/AGENT.md +1 -1
  77. package/app/modules/statsModule/commandConfig.json +58 -0
  78. package/app/modules/statsModule/rankingCommon.js +5 -4
  79. package/app/modules/stickerModule/AGENT.md +1 -1
  80. package/app/modules/stickerModule/addStickerMetadata.js +4 -3
  81. package/app/modules/stickerModule/commandConfig.json +145 -0
  82. package/app/modules/stickerModule/stickerCommand.js +1 -1
  83. package/app/modules/stickerPackModule/AGENT.md +1 -1
  84. package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
  85. package/app/modules/stickerPackModule/commandConfig.json +29 -0
  86. package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
  87. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
  88. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
  89. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
  90. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
  91. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
  92. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
  93. package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
  94. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
  95. package/app/modules/stickerPackModule/stickerPackService.js +13 -6
  96. package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
  97. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
  98. package/app/modules/systemMetricsModule/AGENT.md +1 -1
  99. package/app/modules/systemMetricsModule/commandConfig.json +29 -0
  100. package/app/modules/systemMetricsModule/pingCommand.js +6 -5
  101. package/app/modules/tiktokModule/AGENT.md +1 -1
  102. package/app/modules/tiktokModule/commandConfig.json +29 -0
  103. package/app/modules/tiktokModule/tiktokCommand.js +2 -1
  104. package/app/modules/userModule/AGENT.md +1 -1
  105. package/app/modules/userModule/commandConfig.json +29 -0
  106. package/app/modules/userModule/userCommand.js +72 -23
  107. package/app/modules/waifuPicsModule/AGENT.md +57 -27
  108. package/app/modules/waifuPicsModule/commandConfig.json +87 -0
  109. package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
  110. package/app/observability/metrics.js +136 -0
  111. package/app/services/ai/commandConfigEnrichmentService.js +229 -47
  112. package/app/services/ai/conversationRouterService.js +4 -3
  113. package/app/services/ai/geminiService.js +132 -7
  114. package/app/services/ai/geminiService.test.js +59 -2
  115. package/app/services/ai/globalModuleAiHelpService.js +3 -2
  116. package/app/services/ai/messageCommandExecutionService.js +2 -1
  117. package/app/services/ai/moduleAiHelpCoreService.js +45 -14
  118. package/app/services/ai/moduleToolExecutorService.js +3 -2
  119. package/app/services/ai/moduleToolRegistryService.js +2 -1
  120. package/app/services/ai/toolCandidateSelectorService.js +6 -5
  121. package/app/services/auth/googleWebLinkService.js +3 -2
  122. package/app/services/auth/whatsappLoginLinkService.js +3 -2
  123. package/app/services/external/pokeApiService.js +4 -3
  124. package/app/services/group/groupMetadataService.js +24 -1
  125. package/app/services/infra/dbWriteQueue.js +57 -26
  126. package/app/services/infra/featureFlagService.js +2 -1
  127. package/app/services/messaging/captchaService.js +3 -2
  128. package/app/services/messaging/newsBroadcastService.js +846 -29
  129. package/app/services/multiSession/assignmentBalancerService.js +457 -0
  130. package/app/services/multiSession/groupOwnershipRepository.js +381 -0
  131. package/app/services/multiSession/groupOwnershipService.js +890 -0
  132. package/app/services/multiSession/groupOwnershipService.test.js +309 -0
  133. package/app/services/multiSession/sessionRegistryService.js +293 -0
  134. package/app/services/sticker/stickerFocusService.js +11 -10
  135. package/app/store/aiPromptStore.js +36 -19
  136. package/app/store/conversationSessionStore.js +7 -6
  137. package/app/store/groupConfigStore.js +41 -5
  138. package/app/store/premiumUserStore.js +21 -7
  139. package/app/utils/antiLink/antiLinkModule.js +352 -16
  140. package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
  141. package/app/workers/aiLearningWorker.js +6 -5
  142. package/app/workers/commandConfigEnrichmentWorker.js +4 -3
  143. package/database/index.js +14 -8
  144. package/database/migrations/20260307_d0_hardening_down.sql +1 -1
  145. package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
  146. package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
  147. package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
  148. package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
  149. package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
  150. package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
  151. package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
  152. package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
  153. package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
  154. package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
  155. package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
  156. package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
  157. package/database/schema.sql +102 -1
  158. package/docker-compose.yml +4 -1
  159. package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
  160. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
  161. package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
  162. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
  163. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
  164. package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
  165. package/docs/security/omnizap-static-security-headers.conf +25 -0
  166. package/docs/wiki/Home.md +1 -1
  167. package/ecosystem.prod.config.cjs +32 -12
  168. package/index.js +57 -23
  169. package/observability/alert-rules.yml +20 -0
  170. package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
  171. package/observability/mysql-setup.sql +4 -4
  172. package/observability/system-admin-observability.md +26 -0
  173. package/package.json +20 -6
  174. package/public/apple-touch-icon.png +0 -0
  175. package/public/comandos/commands-catalog.json +2853 -3326
  176. package/public/favicon-16x16.png +0 -0
  177. package/public/favicon-32x32.png +0 -0
  178. package/public/favicon.ico +0 -0
  179. package/public/js/apps/apiDocsApp.js +3 -2
  180. package/public/js/apps/commandsReactApp.js +280 -99
  181. package/public/js/apps/createPackApp.js +11 -10
  182. package/public/js/apps/homeReactApp.js +181 -130
  183. package/public/js/apps/loginReactApp.js +1 -1
  184. package/public/js/apps/stickersApp.js +263 -110
  185. package/public/js/apps/termsReactApp.js +73 -24
  186. package/public/js/apps/userApp.js +4 -3
  187. package/public/js/apps/userPasswordResetReactApp.js +406 -0
  188. package/public/js/apps/userReactApp.js +355 -280
  189. package/public/js/apps/userSystemAdmReactApp.js +1506 -0
  190. package/public/pages/api-docs.html +1 -1
  191. package/public/pages/aup.html +2 -2
  192. package/public/pages/dpa.html +3 -3
  193. package/public/pages/licenca.html +4 -4
  194. package/public/pages/login.html +1 -1
  195. package/public/pages/notice-and-takedown.html +2 -2
  196. package/public/pages/politica-de-privacidade.html +6 -6
  197. package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
  198. package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
  199. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
  200. package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
  201. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
  202. package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
  203. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
  204. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
  205. package/public/pages/stickers-admin.html +1 -1
  206. package/public/pages/stickers-create.html +1 -1
  207. package/public/pages/stickers.html +6 -6
  208. package/public/pages/suboperadores.html +2 -2
  209. package/public/pages/termos-de-uso-texto-integral.html +6 -6
  210. package/public/pages/termos-de-uso.html +3 -3
  211. package/public/pages/user-password-reset.html +4 -5
  212. package/public/pages/user-systemadm.html +9 -463
  213. package/public/pages/user.html +2 -2
  214. package/scripts/clear-whatsapp-session.sh +123 -0
  215. package/scripts/core-ai-mode.mjs +163 -0
  216. package/scripts/deploy.sh +11 -1
  217. package/scripts/email-broadcast-terms-update.mjs +2 -1
  218. package/scripts/enrich-command-config-ux-openai.mjs +492 -0
  219. package/scripts/generate-commands-catalog.mjs +166 -2
  220. package/scripts/generate-module-agents.mjs +2 -1
  221. package/scripts/generate-seo-satellite-pages.mjs +5 -4
  222. package/scripts/github-deploy-notify.mjs +2 -1
  223. package/scripts/github-release-notify.mjs +25 -10
  224. package/scripts/new-whatsapp-session.sh +317 -0
  225. package/scripts/release.sh +2 -19
  226. package/scripts/security-smoketest.mjs +6 -5
  227. package/scripts/security-web-surface-check.mjs +218 -0
  228. package/scripts/sticker-catalog-loadtest.mjs +5 -4
  229. package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
  230. package/server/auth/jwt/webJwtService.js +1 -1
  231. package/server/auth/stickerCatalogAuthContext.js +2 -1
  232. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
  233. package/server/auth/userPassword/userPasswordAuthService.js +2 -1
  234. package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
  235. package/server/auth/webAccount/webAccountHandlers.js +9 -10
  236. package/server/controllers/admin/adminPanelHandlers.js +267 -16
  237. package/server/controllers/admin/systemAdminController.js +267 -0
  238. package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
  239. package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
  240. package/server/controllers/sticker/stickerCatalogController.js +23 -36
  241. package/server/controllers/system/contactController.js +9 -17
  242. package/server/controllers/system/githubController.js +3 -2
  243. package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
  244. package/server/controllers/system/systemController.js +254 -1
  245. package/server/controllers/system/systemMetricsController.js +2 -1
  246. package/server/controllers/userController.js +6 -0
  247. package/server/email/emailTemplateService.js +5 -3
  248. package/server/http/httpServer.js +11 -6
  249. package/server/middleware/rateLimit.js +2 -1
  250. package/server/middleware/securityHeaders.js +20 -1
  251. package/server/routes/admin/systemAdminRouter.js +6 -0
  252. package/server/routes/indexRouter.js +30 -6
  253. package/server/routes/observability/grafanaProxyRouter.js +254 -0
  254. package/server/routes/static/staticPageRouter.js +27 -1
  255. package/server/utils/publicContact.js +31 -0
  256. package/utils/time/timeModule.js +135 -0
  257. package/utils/time/timeModule.test.js +65 -0
  258. package/utils/whatsapp/contactEnv.js +39 -0
  259. package/vite.config.mjs +7 -1
  260. package/public/assets/images/brand-icon-192.png +0 -0
  261. package/scripts/sync-readme-snapshot.mjs +0 -133
Binary file
Binary file
Binary file
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import React, { useEffect, useState } from 'react';
2
3
  import { createRoot } from 'react-dom/client';
3
4
 
@@ -30,7 +31,7 @@ function StatusPanel() {
30
31
  let active = true;
31
32
 
32
33
  const load = async () => {
33
- const start = Date.now();
34
+ const start = __timeNowMs();
34
35
  try {
35
36
  const response = await fetch('/api/home-bootstrap');
36
37
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
@@ -43,7 +44,7 @@ function StatusPanel() {
43
44
  setState({
44
45
  loading: false,
45
46
  ok: true,
46
- latencyMs: Date.now() - start,
47
+ latencyMs: __timeNowMs() - start,
47
48
  cpu: Number.isFinite(Number(host.cpu_percent)) ? `${Number(host.cpu_percent).toFixed(2)}%` : 'n/d',
48
49
  ram: host.memory_used && host.memory_total ? `${host.memory_used} / ${host.memory_total} (${Number(host.memory_percent || 0).toFixed(2)}%)` : 'n/d',
49
50
  uptime: process.uptime || 'n/d',
@@ -30,11 +30,76 @@ const CommandDetailsPage = ({ command, onClose, devMode }) => {
30
30
  if (!command) return null;
31
31
  const [copyStatus, setCopyStatus] = useState({});
32
32
 
33
+ const toList = (value) => {
34
+ if (!Array.isArray(value)) return [];
35
+ return value.map((item) => String(item || '').trim()).filter(Boolean);
36
+ };
37
+
38
+ const metodosDeUso = toList(command.metodos_de_uso);
39
+ const resumoUsuario = String(command.resumo_usuario || command.descricao || `Use /${command.name} para executar esta ação.`).trim();
40
+ const resumoOrigem = String(command.resumo_usuario_origem || '').trim();
41
+ const resumoPendente = Boolean(command.resumo_usuario_revisao_pendente);
42
+
43
+ const quandoUsar = toList(command.quando_usar);
44
+ const respostaEsperada = toList(command.resposta_esperada);
45
+ const errosComuns = toList(command.erros_comuns_usuario);
46
+ const passosErro = toList(command.passos_se_der_erro);
47
+
48
+ const fallbackUso = metodosDeUso[0] || `/${command.name}`;
49
+ const exemplosReais = (Array.isArray(command.exemplos_reais) ? command.exemplos_reais : [])
50
+ .map((example, index) => {
51
+ if (typeof example === 'string') {
52
+ const comando = String(example || '').trim();
53
+ if (!comando) return null;
54
+ return {
55
+ situacao: `Exemplo real ${index + 1} para usar o comando.`,
56
+ comando,
57
+ resposta_esperada: respostaEsperada[0] || 'O bot confirma a execução com uma resposta clara.',
58
+ variacao: '',
59
+ };
60
+ }
61
+
62
+ if (!example || typeof example !== 'object' || Array.isArray(example)) return null;
63
+
64
+ const situacao = String(example.situacao || example.cenario || example.contexto || '').trim();
65
+ const comando = String(example.comando || example.command || example.uso || '').trim();
66
+ const resposta = String(example.resposta_esperada || example.expected_response || example.resposta || '').trim();
67
+ const variacao = String(example.variacao || example.outcome_variation || '').trim();
68
+
69
+ if (!comando) return null;
70
+ return {
71
+ situacao: situacao || `Exemplo real ${index + 1} para usar o comando.`,
72
+ comando,
73
+ resposta_esperada: resposta || respostaEsperada[0] || 'O bot responde confirmando o resultado.',
74
+ variacao,
75
+ };
76
+ })
77
+ .filter(Boolean);
78
+
79
+ if (!exemplosReais.length) {
80
+ exemplosReais.push({
81
+ situacao: `Você quer usar /${command.name} no dia a dia.`,
82
+ comando: fallbackUso,
83
+ resposta_esperada: respostaEsperada[0] || 'O bot responde confirmando o resultado.',
84
+ variacao: respostaEsperada[1] || '',
85
+ });
86
+ }
87
+
88
+ const quandoUsarComFallback = quandoUsar.length ? quandoUsar : [`Quando você precisa executar ${command.descricao || `a ação do comando /${command.name}`}.`, command.requirements?.group ? 'Use dentro de grupos.' : 'Pode ser usado em grupo ou no privado.', command.premium ? 'Disponível para usuários Premium.' : ''].filter(Boolean);
89
+
90
+ const respostaEsperadaComFallback = respostaEsperada.length ? respostaEsperada : ['Sucesso: o bot confirma a execução.', 'Formato incorreto: o bot mostra como usar corretamente.', 'Permissão: o bot informa quando faltar acesso.'];
91
+
92
+ const errosComunsComFallback = errosComuns.length ? errosComuns : ['Digitar o comando fora do formato esperado.', command.requirements?.group ? 'Tentar usar fora de grupo.' : '', command.requirements?.admin ? 'Tentar usar sem ser admin.' : '', command.premium ? 'Tentar usar sem plano Premium ativo.' : ''].filter(Boolean);
93
+
94
+ const passosErroComFallback = passosErro.length ? passosErro : ['Copie um exemplo desta página e teste sem alterar.', 'Confira se você está no local correto (grupo ou privado).', 'Se continuar com erro, fale com o admin no privado.'];
95
+
33
96
  const handleCopy = (text, id) => {
34
- navigator.clipboard.writeText(text);
35
- setCopyStatus({ ...copyStatus, [id]: true });
97
+ const copyText = String(text || '').trim();
98
+ if (!copyText) return;
99
+ navigator.clipboard?.writeText(copyText).catch(() => {});
100
+ setCopyStatus((prev) => ({ ...prev, [id]: true }));
36
101
  setTimeout(() => {
37
- setCopyStatus({ ...copyStatus, [id]: false });
102
+ setCopyStatus((prev) => ({ ...prev, [id]: false }));
38
103
  }, 2000);
39
104
  };
40
105
 
@@ -55,25 +120,26 @@ const CommandDetailsPage = ({ command, onClose, devMode }) => {
55
120
 
56
121
  <div className="sticky top-0 z-50 bg-[#020617]/60 backdrop-blur-xl border-b border-white/5">
57
122
  <div className="container mx-auto px-4 h-16 flex items-center justify-between">
58
- <button onClick=${onClose} className="btn btn-ghost group pl-0 hover:bg-transparent">
59
- <div className="w-10 h-10 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center group-hover:bg-primary group-hover:text-primary-content group-hover:border-primary transition-all duration-300">
123
+ <button onClick=${onClose} className="btn btn-ghost group pl-0 hover:bg-transparent min-h-0 h-auto py-2">
124
+ <div className="w-9 h-9 sm:w-10 sm:h-10 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center group-hover:bg-primary group-hover:text-primary-content group-hover:border-primary transition-all duration-300">
60
125
  <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M15 19l-7-7 7-7" /></svg>
61
126
  </div>
62
127
  <span className="hidden sm:inline text-xs font-black uppercase tracking-widest ml-3 opacity-50 group-hover:opacity-100 transition-opacity">Voltar ao Catálogo</span>
128
+ <span className="sm:hidden text-[10px] font-black uppercase tracking-widest ml-2 opacity-50">Voltar</span>
63
129
  </button>
64
130
 
65
131
  <div className="flex items-center gap-3">
66
132
  <div className="text-right">
67
- <p className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">${command.category_label}</p>
133
+ <p className="text-[9px] sm:text-[10px] font-black uppercase tracking-[0.2em] text-primary">${command.category_label}</p>
68
134
  <p className="text-[8px] font-bold opacity-30 uppercase tracking-widest hidden sm:block">Ref. Doc V3.5</p>
69
135
  </div>
70
- <div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center text-xl border border-primary/20 shadow-[0_0_20px_rgba(34,197,94,0.1)]">${command.category_icon || '🧩'}</div>
136
+ <div className="w-9 h-9 sm:w-10 sm:h-10 rounded-xl bg-primary/10 flex items-center justify-center text-lg sm:text-xl border border-primary/20 shadow-[0_0_20px_rgba(34,197,94,0.1)]">${command.category_icon || '🧩'}</div>
71
137
  </div>
72
138
  </div>
73
139
  </div>
74
140
 
75
141
  <main className="container mx-auto max-w-4xl px-4 py-8 lg:py-16 relative z-10">
76
- <div className="space-y-12">
142
+ <div className="space-y-12 sm:space-y-16">
77
143
  <header className="space-y-6 text-center sm:text-left">
78
144
  <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-[10px] font-black uppercase tracking-widest">
79
145
  <span className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse"></span>
@@ -82,10 +148,10 @@ const CommandDetailsPage = ({ command, onClose, devMode }) => {
82
148
 
83
149
  <div className="space-y-4">
84
150
  <div className="flex flex-wrap items-center justify-center sm:justify-start gap-4">
85
- <h1 className="text-5xl sm:text-6xl lg:text-8xl font-black tracking-tighter text-white">/<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">${command.name}</span></h1>
86
- ${command.premium && html` <div className="badge badge-warning h-10 px-6 font-black text-[10px] uppercase tracking-[0.2em] shadow-[0_0_30px_rgba(251,191,36,0.2)] border-none">Premium</div> `}
151
+ <h1 className="text-4xl sm:text-7xl lg:text-8xl font-black tracking-tighter text-white break-words">/<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">${command.name}</span></h1>
152
+ ${command.premium && html` <div className="badge badge-warning h-8 sm:h-10 px-4 sm:px-6 font-black text-[9px] sm:text-[10px] uppercase tracking-[0.2em] shadow-[0_0_30px_rgba(251,191,36,0.2)] border-none">Premium</div> `}
87
153
  </div>
88
- <p className="text-lg sm:text-xl lg:text-2xl text-white/60 leading-relaxed font-medium max-w-3xl mx-auto sm:mx-0">${command.descricao}</p>
154
+ <p className="text-lg sm:text-xl lg:text-2xl text-white/60 leading-relaxed font-medium max-w-3xl mx-auto sm:mx-0 break-words">${command.descricao}</p>
89
155
  </div>
90
156
 
91
157
  <div className="flex flex-wrap justify-center sm:justify-start gap-2 pt-2">
@@ -101,112 +167,227 @@ const CommandDetailsPage = ({ command, onClose, devMode }) => {
101
167
 
102
168
  <section className="space-y-6">
103
169
  <div className="flex items-center gap-4">
104
- <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Como usar agora</h3>
170
+ <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Resumo rápido</h3>
105
171
  <div className="flex-1 h-px bg-white/5"></div>
106
172
  </div>
107
- <div className="grid gap-4">
108
- ${(command.metodos_de_uso || []).map(
109
- (usage, idx) => html`
110
- <div key=${idx} className="group relative">
111
- <div className="absolute inset-0 bg-primary/5 blur-xl opacity-0 group-hover:opacity-100 transition-opacity rounded-[2.5rem]"></div>
112
- <div className="relative flex flex-col sm:flex-row items-stretch sm:items-center gap-4 p-1 rounded-[2rem] bg-white/[0.03] border border-white/5 group-hover:border-primary/30 transition-all duration-300">
113
- <code className="flex-1 px-6 py-5 sm:py-6 font-mono text-sm sm:text-base text-primary/80 break-all"> ${usage} </code>
114
- <button onClick=${() => handleCopy(usage, `usage-${idx}`)} className=${`px-8 py-4 sm:py-6 rounded-2xl sm:rounded-r-[1.8rem] sm:rounded-l-none font-black text-[10px] uppercase tracking-widest transition-all ${copyStatus[`usage-${idx}`] ? 'bg-success text-white' : 'bg-white/5 hover:bg-primary hover:text-primary-content'}`}>${copyStatus[`usage-${idx}`] ? 'Copiado!' : 'Copiar'}</button>
115
- </div>
173
+ <div className="relative p-6 sm:p-8 rounded-[1.5rem] sm:rounded-[2rem] bg-white/[0.03] border border-white/10 space-y-4 overflow-hidden">
174
+ <div className="absolute -top-10 -right-10 w-28 h-28 rounded-full bg-primary/10 blur-3xl"></div>
175
+ <div className="relative flex flex-wrap items-center gap-2">${resumoPendente && html` <span className="badge badge-info badge-sm h-7 px-3 font-bold uppercase tracking-wider">Resumo por IA · Revisão pendente</span> `} ${!resumoPendente && resumoOrigem === 'manual' && html` <span className="badge badge-success badge-sm h-7 px-3 font-bold uppercase tracking-wider">Resumo revisado</span> `}</div>
176
+ <p className="relative text-base sm:text-lg text-white/80 leading-relaxed">${resumoUsuario}</p>
177
+ </div>
178
+ </section>
179
+
180
+ <section className="space-y-6">
181
+ <div className="flex items-center gap-4">
182
+ <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Quando usar</h3>
183
+ <div className="flex-1 h-px bg-white/5"></div>
184
+ </div>
185
+ <div className="grid gap-3">
186
+ ${quandoUsarComFallback.map(
187
+ (item, idx) => html`
188
+ <div key=${`when-${idx}`} className="p-4 rounded-2xl bg-white/[0.02] border border-white/5 flex items-start gap-3">
189
+ <span className="mt-0.5 text-primary">•</span>
190
+ <p className="text-sm sm:text-base text-white/75 leading-relaxed">${item}</p>
116
191
  </div>
117
192
  `,
118
193
  )}
119
194
  </div>
120
195
  </section>
121
196
 
122
- ${command.arguments?.length > 0 &&
123
- html`
124
- <section className="space-y-6">
125
- <div className="flex items-center gap-4">
126
- <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Configurações e Argumentos</h3>
127
- <div className="flex-1 h-px bg-white/5"></div>
128
- </div>
129
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
130
- ${command.arguments.map(
131
- (arg) => html`
132
- <div key=${arg.name} className="group p-6 rounded-[2rem] bg-white/[0.02] border border-white/5 hover:border-primary/20 transition-all duration-300">
133
- <div className="flex items-start justify-between mb-4">
134
- <div className="space-y-1">
135
- <h4 className="text-lg font-black text-white group-hover:text-primary transition-colors">${arg.name}</h4>
136
- <span className="inline-block text-[9px] font-bold text-white/30 font-mono uppercase tracking-widest bg-white/5 px-2 py-0.5 rounded"> Type: ${arg.type} </span>
137
- </div>
138
- <span className=${`text-[8px] font-black uppercase px-3 py-1 rounded-full border ${arg.required ? 'bg-error/10 text-error border-error/20' : 'bg-white/5 text-white/30 border-white/10'}`}> ${arg.required ? 'Obrigatório' : 'Opcional'} </span>
197
+ <section className="space-y-6">
198
+ <div className="flex items-center gap-4">
199
+ <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Exemplos reais</h3>
200
+ <div className="flex-1 h-px bg-white/5"></div>
201
+ </div>
202
+ <div className="grid gap-5">
203
+ ${exemplosReais.map(
204
+ (example, idx) => html`
205
+ <article key=${`example-${idx}`} className="p-5 sm:p-6 rounded-[1.5rem] bg-white/[0.03] border border-white/10 space-y-5">
206
+ <div className="space-y-1">
207
+ <p className="text-[9px] font-black uppercase tracking-[0.2em] text-primary/70">Situação real</p>
208
+ <p className="text-sm sm:text-base text-white/80 leading-relaxed">${example.situacao}</p>
209
+ </div>
210
+
211
+ <div className="space-y-2">
212
+ <p className="text-[9px] font-black uppercase tracking-[0.2em] text-white/40">Comando pronto</p>
213
+ <div className="relative flex flex-col sm:flex-row items-stretch sm:items-center gap-0 sm:gap-4 p-1 rounded-2xl bg-[#0b1124] border border-white/10">
214
+ <code className="flex-1 px-5 py-4 sm:px-6 sm:py-4 font-mono text-sm text-primary/80 break-all leading-relaxed">${example.comando}</code>
215
+ <button onClick=${() => handleCopy(example.comando, `example-cmd-${idx}`)} className=${`px-8 py-3.5 rounded-2xl sm:rounded-r-[1.2rem] sm:rounded-l-none font-black text-[10px] uppercase tracking-widest transition-all ${copyStatus[`example-cmd-${idx}`] ? 'bg-success text-white' : 'bg-white/5 hover:bg-primary hover:text-primary-content'}`}>${copyStatus[`example-cmd-${idx}`] ? 'Copiado!' : 'Copiar'}</button>
139
216
  </div>
140
- <p className="text-sm text-white/50 font-medium leading-relaxed">${arg.description}</p>
141
217
  </div>
142
- `,
143
- )}
144
- </div>
145
- </section>
146
- `}
147
-
148
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-6 pt-6">
149
- <section className="p-8 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-6 relative overflow-hidden group">
150
- <div className="absolute -right-8 -bottom-8 w-32 h-32 bg-primary/5 blur-2xl rounded-full group-hover:bg-primary/10 transition-colors"></div>
151
- <h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-white/30 relative z-10">Specs Técnicas</h3>
152
- <div className="grid grid-cols-2 gap-y-8 relative z-10">
153
- <div>
154
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Versão</p>
155
- <p className="text-base font-black text-white">${command.technical?.version || '1.0.0'}</p>
156
- </div>
157
- <div>
158
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Estabilidade</p>
159
- <p className="text-base font-black text-emerald-400">${command.technical?.stability || 'Stable'}</p>
160
- </div>
161
- <div>
162
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Risco</p>
163
- <p className="text-base font-black ${command.technical?.risk_level !== 'low' ? 'text-rose-500' : 'text-emerald-400'}">${command.technical?.risk_level?.toUpperCase() || 'LOW'}</p>
218
+
219
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
220
+ <div className="p-4 rounded-xl bg-white/[0.02] border border-white/5">
221
+ <p className="text-[9px] font-black uppercase tracking-[0.2em] text-white/40 mb-2">Resposta esperada</p>
222
+ <p className="text-sm text-white/75 leading-relaxed">${example.resposta_esperada}</p>
223
+ </div>
224
+ <div className="p-4 rounded-xl bg-white/[0.02] border border-white/5">
225
+ <p className="text-[9px] font-black uppercase tracking-[0.2em] text-white/40 mb-2">Variação possível</p>
226
+ <p className="text-sm text-white/75 leading-relaxed">${example.variacao || 'Se faltar parâmetro ou permissão, o bot explica o próximo passo para corrigir.'}</p>
227
+ </div>
228
+ </div>
229
+ </article>
230
+ `,
231
+ )}
232
+ </div>
233
+ </section>
234
+
235
+ <section className="space-y-6">
236
+ <div className="flex items-center gap-4">
237
+ <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">O que esperar de resposta</h3>
238
+ <div className="flex-1 h-px bg-white/5"></div>
239
+ </div>
240
+ <div className="grid gap-3">
241
+ ${respostaEsperadaComFallback.map(
242
+ (item, idx) => html`
243
+ <div key=${`expected-${idx}`} className="p-4 rounded-2xl bg-white/[0.02] border border-white/5 flex items-start gap-3">
244
+ <span className="mt-0.5 text-emerald-400">✓</span>
245
+ <p className="text-sm sm:text-base text-white/75 leading-relaxed">${item}</p>
246
+ </div>
247
+ `,
248
+ )}
249
+ </div>
250
+ </section>
251
+
252
+ <section className="space-y-6">
253
+ <div className="flex items-center gap-4">
254
+ <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Se der erro</h3>
255
+ <div className="flex-1 h-px bg-white/5"></div>
256
+ </div>
257
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
258
+ <div className="p-5 rounded-[1.3rem] bg-white/[0.03] border border-white/10 space-y-4">
259
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-amber-300">Erros comuns</p>
260
+ <div className="space-y-2">
261
+ ${errosComunsComFallback.map(
262
+ (item, idx) => html`
263
+ <div key=${`common-error-${idx}`} className="text-sm text-white/75 leading-relaxed flex items-start gap-2">
264
+ <span className="text-amber-300">•</span>
265
+ <span>${item}</span>
266
+ </div>
267
+ `,
268
+ )}
164
269
  </div>
165
- <div>
166
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">ID Sistema</p>
167
- <p className="text-[10px] font-mono font-bold text-white/40 truncate">${command.id}</p>
270
+ </div>
271
+
272
+ <div className="p-5 rounded-[1.3rem] bg-white/[0.03] border border-white/10 space-y-4">
273
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-primary">O que fazer agora</p>
274
+ <div className="space-y-2">
275
+ ${passosErroComFallback.map(
276
+ (item, idx) => html`
277
+ <div key=${`error-step-${idx}`} className="text-sm text-white/75 leading-relaxed flex items-start gap-2">
278
+ <span className="text-primary font-black">${idx + 1}.</span>
279
+ <span>${item}</span>
280
+ </div>
281
+ `,
282
+ )}
168
283
  </div>
169
284
  </div>
170
- </section>
171
-
172
- ${command.technical?.collected_data?.length > 0 &&
173
- html`
174
- <section className="p-8 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-6 relative overflow-hidden group">
175
- <div className="absolute -right-8 -bottom-8 w-32 h-32 bg-emerald-500/5 blur-2xl rounded-full group-hover:bg-emerald-500/10 transition-colors"></div>
176
- <h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-white/30 relative z-10">Privacidade e Dados</h3>
177
- <div className="flex flex-wrap gap-2 relative z-10">${command.technical.collected_data.map((data) => html` <span key=${data} className="text-[10px] font-bold bg-white/5 px-4 py-2 rounded-xl border border-white/10 text-white/60">${data}</span> `)}</div>
178
- <p className="text-[9px] text-white/20 font-medium leading-relaxed italic relative z-10">* Estes dados são processados apenas para execução do comando.</p>
179
- </section>
180
- `}
181
- </div>
285
+ </div>
286
+ </section>
182
287
 
183
- ${devMode &&
184
- html`
185
- <section className="space-y-6 animate-in slide-in-from-bottom-8 duration-1000">
186
- <div className="flex items-center gap-4">
187
- <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-warning/30">Developer Metadata</h3>
188
- <div className="flex-1 h-px bg-warning/10"></div>
288
+ <details className="group rounded-[1.5rem] border border-white/10 bg-white/[0.02] open:bg-white/[0.03] transition-colors">
289
+ <summary className="list-none cursor-pointer px-6 py-5 flex items-center justify-between gap-4">
290
+ <div>
291
+ <p className="text-[10px] font-black uppercase tracking-[0.3em] text-white/40">Área técnica</p>
292
+ <p className="text-xs text-white/50 mt-1">Especificações avançadas e metadados do comando.</p>
189
293
  </div>
190
- <div className="relative group">
191
- <div className="absolute inset-0 bg-warning/5 blur-3xl opacity-20"></div>
192
- <div className="relative bg-[#020617] border border-warning/10 rounded-[2.5rem] overflow-hidden">
193
- <div className="bg-warning/5 px-8 py-3 border-b border-warning/10 flex items-center justify-between">
194
- <span className="text-[9px] font-black uppercase tracking-widest text-warning/60 font-mono">command_schema.json</span>
195
- <button onClick=${() => handleCopy(JSON.stringify(command, null, 2), 'raw-json')} className=${`text-[9px] font-black uppercase tracking-widest transition-colors ${copyStatus['raw-json'] ? 'text-success' : 'text-warning/40 hover:text-warning'}`}>${copyStatus['raw-json'] ? 'Copiado!' : 'Copiar JSON'}</button>
294
+ <span className="w-8 h-8 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center group-open:rotate-180 transition-transform">
295
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4 text-white/60" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M19 9l-7 7-7-7" /></svg>
296
+ </span>
297
+ </summary>
298
+
299
+ <div className="px-6 pb-6 space-y-6">
300
+ ${metodosDeUso.length > 0 &&
301
+ html`
302
+ <section className="space-y-3">
303
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-white/40">Como usar agora</p>
304
+ <div className="grid gap-3">
305
+ ${metodosDeUso.map(
306
+ (usage, idx) => html`
307
+ <div key=${idx} className="relative flex flex-col sm:flex-row items-stretch sm:items-center gap-0 sm:gap-4 p-1 rounded-2xl bg-[#0b1124] border border-white/10">
308
+ <code className="flex-1 px-5 py-4 sm:px-6 sm:py-4 font-mono text-sm text-primary/80 break-all leading-relaxed">${usage}</code>
309
+ <button onClick=${() => handleCopy(usage, `usage-${idx}`)} className=${`px-8 py-3.5 rounded-2xl sm:rounded-r-[1.2rem] sm:rounded-l-none font-black text-[10px] uppercase tracking-widest transition-all ${copyStatus[`usage-${idx}`] ? 'bg-success text-white' : 'bg-white/5 hover:bg-primary hover:text-primary-content'}`}>${copyStatus[`usage-${idx}`] ? 'Copiado!' : 'Copiar'}</button>
310
+ </div>
311
+ `,
312
+ )}
313
+ </div>
314
+ </section>
315
+ `}
316
+ ${command.arguments?.length > 0 &&
317
+ html`
318
+ <section className="space-y-3">
319
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-white/40">Argumentos</p>
320
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
321
+ ${command.arguments.map(
322
+ (arg) => html`
323
+ <div key=${arg.name} className="p-4 rounded-2xl bg-white/[0.02] border border-white/10">
324
+ <div className="flex items-start justify-between gap-2 mb-2">
325
+ <h4 className="text-sm font-black text-white">${arg.name}</h4>
326
+ <span className=${`text-[8px] font-black uppercase px-2 py-1 rounded-full border ${arg.required ? 'bg-error/10 text-error border-error/20' : 'bg-white/5 text-white/40 border-white/10'}`}>${arg.required ? 'Obrigatório' : 'Opcional'}</span>
327
+ </div>
328
+ <p className="text-[10px] font-mono text-white/40 uppercase tracking-wider mb-2">Tipo: ${arg.type}</p>
329
+ <p className="text-sm text-white/65 leading-relaxed">${arg.description}</p>
330
+ </div>
331
+ `,
332
+ )}
333
+ </div>
334
+ </section>
335
+ `}
336
+
337
+ <section className="grid grid-cols-1 sm:grid-cols-2 gap-4">
338
+ <div className="p-5 rounded-2xl bg-white/[0.02] border border-white/10 space-y-4">
339
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-white/40">Specs técnicas</p>
340
+ <div className="grid grid-cols-2 gap-y-4">
341
+ <div>
342
+ <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Versão</p>
343
+ <p className="text-sm font-black text-white">${command.technical?.version || '1.0.0'}</p>
344
+ </div>
345
+ <div>
346
+ <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Estabilidade</p>
347
+ <p className="text-sm font-black text-emerald-400">${command.technical?.stability || 'stable'}</p>
348
+ </div>
349
+ <div>
350
+ <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Risco</p>
351
+ <p className="text-sm font-black ${command.technical?.risk_level !== 'low' ? 'text-rose-500' : 'text-emerald-400'}">${command.technical?.risk_level?.toUpperCase() || 'LOW'}</p>
352
+ </div>
353
+ <div>
354
+ <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">ID Sistema</p>
355
+ <p className="text-[10px] font-mono font-bold text-white/40 break-all">${command.id}</p>
356
+ </div>
196
357
  </div>
197
- <pre className="p-8 font-mono text-[10px] sm:text-[11px] text-warning/70 overflow-x-auto max-h-[400px] scrollbar-thin scrollbar-thumb-warning/20">
198
- ${JSON.stringify(command, null, 2)}
199
- </pre
200
- >
201
358
  </div>
202
- </div>
203
- </section>
204
- `}
205
359
 
206
- <div className="pt-12 pb-20 text-center">
207
- <button onClick=${onClose} className="group relative inline-flex items-center justify-center">
360
+ <div className="p-5 rounded-2xl bg-white/[0.02] border border-white/10 space-y-4">
361
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-white/40">Privacidade e dados</p>
362
+ ${(command.technical?.collected_data || []).length > 0
363
+ ? html`
364
+ <div className="flex flex-wrap gap-2">${command.technical.collected_data.map((data) => html` <span key=${data} className="text-[10px] font-bold bg-white/5 px-3 py-1.5 rounded-lg border border-white/10 text-white/60">${data}</span> `)}</div>
365
+ <p className="text-[10px] text-white/40 leading-relaxed">Dados processados apenas para executar a funcionalidade solicitada.</p>
366
+ `
367
+ : html`<p className="text-sm text-white/60 leading-relaxed">Este comando não expõe dados técnicos adicionais de coleta.</p>`}
368
+ </div>
369
+ </section>
370
+
371
+ ${devMode &&
372
+ html`
373
+ <section className="space-y-3">
374
+ <p className="text-[10px] font-black uppercase tracking-[0.2em] text-warning/50">Developer Metadata</p>
375
+ <div className="relative bg-[#020617] border border-warning/10 rounded-2xl overflow-hidden">
376
+ <div className="bg-warning/5 px-4 py-3 border-b border-warning/10 flex items-center justify-between gap-4">
377
+ <span className="text-[9px] font-black uppercase tracking-widest text-warning/60 font-mono">command_schema.json</span>
378
+ <button onClick=${() => handleCopy(JSON.stringify(command, null, 2), 'raw-json')} className=${`text-[9px] font-black uppercase tracking-widest transition-colors ${copyStatus['raw-json'] ? 'text-success' : 'text-warning/40 hover:text-warning'}`}>${copyStatus['raw-json'] ? 'Copiado!' : 'Copiar JSON'}</button>
379
+ </div>
380
+ <pre className="p-4 sm:p-6 font-mono text-[9px] sm:text-[11px] text-warning/70 overflow-x-auto max-h-[380px] scrollbar-thin scrollbar-thumb-warning/20">${JSON.stringify(command, null, 2)}</pre>
381
+ </div>
382
+ </section>
383
+ `}
384
+ </div>
385
+ </details>
386
+
387
+ <div className="pt-8 sm:pt-12 pb-20 text-center">
388
+ <button onClick=${onClose} className="group relative inline-flex items-center justify-center w-full sm:w-auto">
208
389
  <div className="absolute inset-0 bg-primary/20 blur-2xl group-hover:bg-primary/40 transition-colors rounded-2xl"></div>
209
- <div className="relative bg-primary text-primary-content px-12 py-5 rounded-2xl font-black text-xs uppercase tracking-[0.3em] shadow-2xl hover:scale-105 active:scale-95 transition-all">Voltar ao Catálogo</div>
390
+ <div className="relative bg-primary text-primary-content px-12 py-5 rounded-2xl font-black text-xs uppercase tracking-[0.3em] shadow-2xl hover:scale-105 active:scale-95 transition-all w-full sm:w-auto text-center">Voltar ao Catálogo</div>
210
391
  </button>
211
392
  </div>
212
393
  </div>
@@ -515,7 +696,7 @@ const App = () => {
515
696
 
516
697
  <footer className="mt-20 py-16 border-t border-base-200 bg-base-200/20">
517
698
  <div className="container mx-auto px-4 text-center">
518
- <p className="text-[10px] font-bold uppercase tracking-[0.4em] text-base-content/20">© 2026 OMNIZAP SYSTEM · COMMANDS LIBRARY V3.5</p>
699
+ <p className="text-[10px] font-bold uppercase tracking-[0.4em] text-base-content/20">© 2026 OMNIZAP · COMMANDS LIBRARY V3.5</p>
519
700
  </div>
520
701
  </footer>
521
702
  </div>
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
3
  import { createRoot } from 'react-dom/client';
3
4
  import htm from 'htm';
@@ -98,7 +99,7 @@ const readGoogleAuthCache = () => {
98
99
  if (!raw) return null;
99
100
  const parsed = JSON.parse(raw);
100
101
  const savedAt = Number(parsed?.savedAt || 0);
101
- if (savedAt && Date.now() - savedAt > GOOGLE_AUTH_CACHE_MAX_STALE_MS) {
102
+ if (savedAt && __timeNowMs() - savedAt > GOOGLE_AUTH_CACHE_MAX_STALE_MS) {
102
103
  localStorage.removeItem(GOOGLE_AUTH_CACHE_KEY);
103
104
  return null;
104
105
  }
@@ -109,7 +110,7 @@ const readGoogleAuthCache = () => {
109
110
  }
110
111
  if (normalized.expiresAt) {
111
112
  const expiresAt = Number(new Date(normalized.expiresAt));
112
- if (Number.isFinite(expiresAt) && expiresAt <= Date.now()) {
113
+ if (Number.isFinite(expiresAt) && expiresAt <= __timeNowMs()) {
113
114
  localStorage.removeItem(GOOGLE_AUTH_CACHE_KEY);
114
115
  return null;
115
116
  }
@@ -131,7 +132,7 @@ const writeGoogleAuthCache = (authState) => {
131
132
  GOOGLE_AUTH_CACHE_KEY,
132
133
  JSON.stringify({
133
134
  auth: normalized,
134
- savedAt: Date.now(),
135
+ savedAt: __timeNowMs(),
135
136
  }),
136
137
  );
137
138
  } catch {
@@ -216,7 +217,7 @@ const writeUploadTask = (payload) => {
216
217
  PACK_UPLOAD_TASK_KEY,
217
218
  JSON.stringify({
218
219
  ...payload,
219
- updatedAt: Date.now(),
220
+ updatedAt: __timeNowMs(),
220
221
  }),
221
222
  );
222
223
  } catch {
@@ -410,7 +411,7 @@ function CreatePackApp() {
410
411
  const [name, setName] = useState('');
411
412
  const [description, setDescription] = useState('');
412
413
  const [publisher, setPublisher] = useState('');
413
- const [visibility, setVisibility] = useState('public');
414
+ const [visibility, setVisibility] = useState('private');
414
415
  const [tags, setTags] = useState([]);
415
416
  const [tagInput, setTagInput] = useState('');
416
417
  const [suggestedTags, setSuggestedTags] = useState(DEFAULT_SUGGESTED_TAGS);
@@ -630,7 +631,7 @@ function CreatePackApp() {
630
631
  const restored = parsed.files
631
632
  .filter((item) => item && typeof item.dataUrl === 'string' && typeof item.name === 'string')
632
633
  .map((item) => ({
633
- id: String(item.id || `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`),
634
+ id: String(item.id || `${__timeNowMs()}-${Math.random().toString(36).slice(2, 9)}`),
634
635
  file: {
635
636
  name: String(item.name || 'sticker.webp'),
636
637
  size: Number(item.size || 0),
@@ -707,7 +708,7 @@ function CreatePackApp() {
707
708
  hash: String(item?.hash || ''),
708
709
  dataUrl: item.dataUrl,
709
710
  })),
710
- updatedAt: Date.now(),
711
+ updatedAt: __timeNowMs(),
711
712
  };
712
713
 
713
714
  try {
@@ -880,7 +881,7 @@ function CreatePackApp() {
880
881
  selected.map(async (file) => {
881
882
  const dataUrl = await fileToDataUrl(file);
882
883
  return {
883
- id: `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
884
+ id: `${__timeNowMs()}-${Math.random().toString(36).slice(2, 9)}`,
884
885
  file,
885
886
  hash: await computeDataUrlSha256(dataUrl),
886
887
  mediaKind:
@@ -1321,7 +1322,7 @@ function CreatePackApp() {
1321
1322
  setName('');
1322
1323
  setDescription('');
1323
1324
  setPublisher('');
1324
- setVisibility('public');
1325
+ setVisibility('private');
1325
1326
  setTags([]);
1326
1327
  setTagInput('');
1327
1328
  setFiles([]);
@@ -1479,7 +1480,7 @@ function CreatePackApp() {
1479
1480
  </label>
1480
1481
  <label className="block">
1481
1482
  <span className="mb-2 inline-block text-xs font-semibold text-slate-300">Visibilidade</span>
1482
- <select value=${visibility} onChange=${(e) => setVisibility(String(e.target.value || 'public'))} className="h-11 w-full rounded-2xl border border-line/70 bg-panelSoft/80 px-4 text-sm outline-none focus:border-accent/60 md:h-12">
1483
+ <select value=${visibility} onChange=${(e) => setVisibility(String(e.target.value || 'private'))} className="h-11 w-full rounded-2xl border border-line/70 bg-panelSoft/80 px-4 text-sm outline-none focus:border-accent/60 md:h-12">
1483
1484
  <option value="public">Público</option>
1484
1485
  <option value="unlisted">Não listado</option>
1485
1486
  <option value="private">Privado</option>