@omnizap-system/omnizap 2.6.1 → 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 (156) hide show
  1. package/.env.example +54 -9
  2. package/.github/workflows/ci.yml +3 -3
  3. package/.github/workflows/security-runner-hardening.yml +1 -1
  4. package/.github/workflows/security-zap-full-scan.yml +1 -0
  5. package/app/config/index.js +2 -0
  6. package/app/configParts/adminIdentity.js +5 -5
  7. package/app/configParts/baileysConfig.js +226 -55
  8. package/app/configParts/groupUtils.js +5 -0
  9. package/app/configParts/messagePersistenceService.js +143 -3
  10. package/app/configParts/sessionConfig.js +157 -0
  11. package/app/connection/baileysCompatibility.test.js +1 -1
  12. package/app/connection/groupOwnerWriteStateResolver.js +109 -0
  13. package/app/connection/socketController.js +625 -124
  14. package/app/connection/socketController.multiSession.test.js +108 -0
  15. package/app/controllers/messageController.js +1 -1
  16. package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
  17. package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
  18. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
  19. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
  20. package/app/controllers/messageProcessingPipeline.js +88 -9
  21. package/app/controllers/messageProcessingPipeline.test.js +200 -0
  22. package/app/modules/adminModule/AGENT.md +1 -1
  23. package/app/modules/adminModule/commandConfig.json +3318 -1347
  24. package/app/modules/adminModule/groupCommandHandlers.js +856 -14
  25. package/app/modules/adminModule/groupCommandHandlers.test.js +375 -9
  26. package/app/modules/adminModule/groupWarningRepository.js +152 -0
  27. package/app/modules/aiModule/AGENT.md +47 -30
  28. package/app/modules/aiModule/aiConfigRuntime.js +1 -0
  29. package/app/modules/aiModule/catCommand.js +132 -25
  30. package/app/modules/aiModule/commandConfig.json +114 -28
  31. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
  32. package/app/modules/gameModule/AGENT.md +1 -1
  33. package/app/modules/gameModule/commandConfig.json +29 -0
  34. package/app/modules/menuModule/AGENT.md +1 -1
  35. package/app/modules/menuModule/commandConfig.json +45 -10
  36. package/app/modules/menuModule/menuCatalogService.js +190 -0
  37. package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
  38. package/app/modules/menuModule/menuDynamicService.js +511 -0
  39. package/app/modules/menuModule/menuDynamicService.test.js +141 -0
  40. package/app/modules/menuModule/menus.js +36 -5
  41. package/app/modules/playModule/AGENT.md +10 -5
  42. package/app/modules/playModule/commandConfig.json +74 -16
  43. package/app/modules/playModule/playCommandConstants.js +13 -7
  44. package/app/modules/playModule/playCommandCore.js +4 -6
  45. package/app/modules/playModule/{playCommandYtDlpClient.js → playCommandMediaClient.js} +684 -332
  46. package/app/modules/playModule/playConfigRuntime.js +5 -6
  47. package/app/modules/playModule/playModuleCriticalFlows.test.js +44 -59
  48. package/app/modules/quoteModule/AGENT.md +1 -1
  49. package/app/modules/quoteModule/commandConfig.json +29 -0
  50. package/app/modules/rpgPokemonModule/AGENT.md +1 -1
  51. package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
  52. package/app/modules/statsModule/AGENT.md +1 -1
  53. package/app/modules/statsModule/commandConfig.json +58 -0
  54. package/app/modules/stickerModule/AGENT.md +1 -1
  55. package/app/modules/stickerModule/commandConfig.json +145 -0
  56. package/app/modules/stickerPackModule/AGENT.md +1 -1
  57. package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
  58. package/app/modules/stickerPackModule/commandConfig.json +29 -0
  59. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +1 -1
  60. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +78 -57
  61. package/app/modules/stickerPackModule/stickerPackService.js +13 -6
  62. package/app/modules/systemMetricsModule/AGENT.md +1 -1
  63. package/app/modules/systemMetricsModule/commandConfig.json +29 -0
  64. package/app/modules/tiktokModule/AGENT.md +1 -1
  65. package/app/modules/tiktokModule/commandConfig.json +29 -0
  66. package/app/modules/userModule/AGENT.md +1 -1
  67. package/app/modules/userModule/commandConfig.json +29 -0
  68. package/app/modules/waifuPicsModule/AGENT.md +57 -27
  69. package/app/modules/waifuPicsModule/commandConfig.json +87 -0
  70. package/app/observability/metrics.js +136 -0
  71. package/app/services/ai/commandConfigEnrichmentService.js +229 -47
  72. package/app/services/ai/geminiService.js +131 -7
  73. package/app/services/ai/geminiService.test.js +59 -2
  74. package/app/services/ai/moduleAiHelpCoreService.js +33 -4
  75. package/app/services/group/groupMetadataService.js +24 -1
  76. package/app/services/infra/dbWriteQueue.js +51 -21
  77. package/app/services/messaging/newsBroadcastService.js +843 -27
  78. package/app/services/multiSession/assignmentBalancerService.js +457 -0
  79. package/app/services/multiSession/groupOwnershipRepository.js +381 -0
  80. package/app/services/multiSession/groupOwnershipService.js +890 -0
  81. package/app/services/multiSession/groupOwnershipService.test.js +309 -0
  82. package/app/services/multiSession/sessionRegistryService.js +293 -0
  83. package/app/store/aiPromptStore.js +36 -19
  84. package/app/store/groupConfigStore.js +41 -5
  85. package/app/store/premiumUserStore.js +21 -7
  86. package/app/utils/antiLink/antiLinkModule.js +352 -16
  87. package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
  88. package/database/index.js +6 -0
  89. package/database/migrations/20260307_d0_hardening_down.sql +1 -1
  90. package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
  91. package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
  92. package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
  93. package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
  94. package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
  95. package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
  96. package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
  97. package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
  98. package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
  99. package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
  100. package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
  101. package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
  102. package/database/schema.sql +102 -1
  103. package/docker-compose.yml +4 -1
  104. package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
  105. package/docs/compliance/privacy-policy-2026-03-07.md +2 -2
  106. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
  107. package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
  108. package/docs/security/omnizap-static-security-headers.conf +25 -0
  109. package/ecosystem.prod.config.cjs +31 -11
  110. package/index.js +52 -18
  111. package/observability/alert-rules.yml +20 -0
  112. package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
  113. package/observability/mysql-setup.sql +4 -4
  114. package/observability/system-admin-observability.md +26 -0
  115. package/package.json +12 -5
  116. package/public/comandos/commands-catalog.json +2253 -78
  117. package/public/js/apps/commandsReactApp.js +267 -87
  118. package/public/js/apps/createPackApp.js +3 -3
  119. package/public/js/apps/stickersApp.js +255 -103
  120. package/public/js/apps/termsReactApp.js +57 -8
  121. package/public/js/apps/userPasswordResetReactApp.js +406 -0
  122. package/public/js/apps/userReactApp.js +96 -47
  123. package/public/js/apps/userSystemAdmReactApp.js +1506 -0
  124. package/public/pages/politica-de-privacidade.html +1 -1
  125. package/public/pages/stickers.html +5 -5
  126. package/public/pages/termos-de-uso-texto-integral.html +1 -1
  127. package/public/pages/termos-de-uso.html +1 -1
  128. package/public/pages/user-password-reset.html +3 -4
  129. package/public/pages/user-systemadm.html +8 -462
  130. package/public/pages/user.html +1 -1
  131. package/scripts/clear-whatsapp-session.sh +123 -0
  132. package/scripts/core-ai-mode.mjs +163 -0
  133. package/scripts/deploy.sh +10 -0
  134. package/scripts/enrich-command-config-ux-openai.mjs +492 -0
  135. package/scripts/generate-commands-catalog.mjs +155 -0
  136. package/scripts/new-whatsapp-session.sh +317 -0
  137. package/scripts/security-web-surface-check.mjs +218 -0
  138. package/server/controllers/admin/adminPanelHandlers.js +253 -3
  139. package/server/controllers/admin/systemAdminController.js +267 -0
  140. package/server/controllers/sticker/stickerCatalogController.js +9 -23
  141. package/server/controllers/system/contactController.js +9 -17
  142. package/server/controllers/system/stickerCatalogSystemContext.js +27 -6
  143. package/server/controllers/system/systemController.js +254 -1
  144. package/server/controllers/userController.js +6 -0
  145. package/server/email/emailTemplateService.js +3 -2
  146. package/server/http/httpServer.js +8 -4
  147. package/server/middleware/securityHeaders.js +20 -1
  148. package/server/routes/admin/systemAdminRouter.js +6 -0
  149. package/server/routes/indexRouter.js +30 -6
  150. package/server/routes/observability/grafanaProxyRouter.js +254 -0
  151. package/server/routes/static/staticPageRouter.js +27 -1
  152. package/server/utils/publicContact.js +31 -0
  153. package/utils/whatsapp/contactEnv.js +39 -0
  154. package/vite.config.mjs +2 -1
  155. package/app/modules/playModule/local/installYtDlp.js +0 -25
  156. package/app/modules/playModule/local/ytDlpInstaller.js +0 -28
@@ -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
 
@@ -102,107 +167,222 @@ const CommandDetailsPage = ({ command, onClose, devMode }) => {
102
167
 
103
168
  <section className="space-y-6">
104
169
  <div className="flex items-center gap-4">
105
- <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>
106
171
  <div className="flex-1 h-px bg-white/5"></div>
107
172
  </div>
108
- <div className="grid gap-4">
109
- ${(command.metodos_de_uso || []).map(
110
- (usage, idx) => html`
111
- <div key=${idx} className="group relative">
112
- <div className="absolute inset-0 bg-primary/5 blur-xl opacity-0 group-hover:opacity-100 transition-opacity rounded-[1.5rem] sm:rounded-[2.5rem]"></div>
113
- <div className="relative flex flex-col sm:flex-row items-stretch sm:items-center gap-0 sm:gap-4 p-1 rounded-[1.5rem] sm:rounded-[2rem] bg-white/[0.03] border border-white/5 group-hover:border-primary/30 transition-all duration-300">
114
- <code className="flex-1 px-5 py-4 sm:px-6 sm:py-6 font-mono text-sm sm:text-base text-primary/80 break-all leading-relaxed"> ${usage} </code>
115
- <button onClick=${() => handleCopy(usage, `usage-${idx}`)} className=${`px-8 py-3.5 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>
116
- </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>
117
191
  </div>
118
192
  `,
119
193
  )}
120
194
  </div>
121
195
  </section>
122
196
 
123
- ${command.arguments?.length > 0 &&
124
- html`
125
- <section className="space-y-6">
126
- <div className="flex items-center gap-4">
127
- <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-white/20">Configurações e Argumentos</h3>
128
- <div className="flex-1 h-px bg-white/5"></div>
129
- </div>
130
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
131
- ${command.arguments.map(
132
- (arg) => html`
133
- <div key=${arg.name} className="group p-5 sm:p-6 rounded-[1.5rem] sm:rounded-[2rem] bg-white/[0.02] border border-white/5 hover:border-primary/20 transition-all duration-300">
134
- <div className="flex items-start justify-between mb-4">
135
- <div className="space-y-1">
136
- <h4 className="text-base sm:text-lg font-black text-white group-hover:text-primary transition-colors">${arg.name}</h4>
137
- <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>
138
- </div>
139
- <span className=${`text-[8px] font-black uppercase px-2.5 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>
140
216
  </div>
141
- <p className="text-xs sm:text-sm text-white/50 font-medium leading-relaxed">${arg.description}</p>
142
217
  </div>
143
- `,
144
- )}
145
- </div>
146
- </section>
147
- `}
148
-
149
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-6 pt-6">
150
- <section className="p-6 sm:p-8 rounded-[1.5rem] sm:rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-6 relative overflow-hidden group">
151
- <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>
152
- <h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-white/30 relative z-10">Specs Técnicas</h3>
153
- <div className="grid grid-cols-2 gap-y-6 sm:gap-y-8 relative z-10">
154
- <div>
155
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Versão</p>
156
- <p className="text-sm sm:text-base font-black text-white">${command.technical?.version || '1.0.0'}</p>
157
- </div>
158
- <div>
159
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Estabilidade</p>
160
- <p className="text-sm sm:text-base font-black text-emerald-400">${command.technical?.stability || 'Stable'}</p>
161
- </div>
162
- <div>
163
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">Risco</p>
164
- <p className="text-sm sm: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
+ )}
165
269
  </div>
166
- <div>
167
- <p className="text-[9px] font-bold uppercase text-white/20 mb-1 tracking-widest">ID Sistema</p>
168
- <p className="text-[10px] font-mono font-bold text-white/40 truncate" title=${command.id}>${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
+ )}
169
283
  </div>
170
284
  </div>
171
- </section>
172
-
173
- ${command.technical?.collected_data?.length > 0 &&
174
- html`
175
- <section className="p-6 sm:p-8 rounded-[1.5rem] sm:rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-6 relative overflow-hidden group">
176
- <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>
177
- <h3 className="text-[10px] font-black uppercase tracking-[0.3em] text-white/30 relative z-10">Privacidade e Dados</h3>
178
- <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>
179
- <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>
180
- </section>
181
- `}
182
- </div>
285
+ </div>
286
+ </section>
183
287
 
184
- ${devMode &&
185
- html`
186
- <section className="space-y-6 animate-in slide-in-from-bottom-8 duration-1000">
187
- <div className="flex items-center gap-4">
188
- <h3 className="text-[10px] font-black uppercase tracking-[0.4em] text-warning/30">Developer Metadata</h3>
189
- <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>
190
293
  </div>
191
- <div className="relative group">
192
- <div className="absolute inset-0 bg-warning/5 blur-3xl opacity-20"></div>
193
- <div className="relative bg-[#020617] border border-warning/10 rounded-[1.5rem] sm:rounded-[2.5rem] overflow-hidden">
194
- <div className="bg-warning/5 px-6 sm:px-8 py-3 border-b border-warning/10 flex items-center justify-between">
195
- <span className="text-[9px] font-black uppercase tracking-widest text-warning/60 font-mono">command_schema.json</span>
196
- <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>
197
357
  </div>
198
- <pre className="p-6 sm:p-8 font-mono text-[9px] sm:text-[11px] text-warning/70 overflow-x-auto max-h-[400px] scrollbar-thin scrollbar-thumb-warning/20">
199
- ${JSON.stringify(command, null, 2)}
200
- </pre
201
- >
202
358
  </div>
203
- </div>
204
- </section>
205
- `}
359
+
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>
206
386
 
207
387
  <div className="pt-8 sm:pt-12 pb-20 text-center">
208
388
  <button onClick=${onClose} className="group relative inline-flex items-center justify-center w-full sm:w-auto">
@@ -411,7 +411,7 @@ function CreatePackApp() {
411
411
  const [name, setName] = useState('');
412
412
  const [description, setDescription] = useState('');
413
413
  const [publisher, setPublisher] = useState('');
414
- const [visibility, setVisibility] = useState('public');
414
+ const [visibility, setVisibility] = useState('private');
415
415
  const [tags, setTags] = useState([]);
416
416
  const [tagInput, setTagInput] = useState('');
417
417
  const [suggestedTags, setSuggestedTags] = useState(DEFAULT_SUGGESTED_TAGS);
@@ -1322,7 +1322,7 @@ function CreatePackApp() {
1322
1322
  setName('');
1323
1323
  setDescription('');
1324
1324
  setPublisher('');
1325
- setVisibility('public');
1325
+ setVisibility('private');
1326
1326
  setTags([]);
1327
1327
  setTagInput('');
1328
1328
  setFiles([]);
@@ -1480,7 +1480,7 @@ function CreatePackApp() {
1480
1480
  </label>
1481
1481
  <label className="block">
1482
1482
  <span className="mb-2 inline-block text-xs font-semibold text-slate-300">Visibilidade</span>
1483
- <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">
1484
1484
  <option value="public">Público</option>
1485
1485
  <option value="unlisted">Não listado</option>
1486
1486
  <option value="private">Privado</option>