@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.
- package/.env.example +58 -13
- package/.github/workflows/ci.yml +5 -5
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/db-migration-check.yml +2 -2
- package/.github/workflows/dependency-review.yml +1 -1
- package/.github/workflows/deploy.yml +2 -2
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security-attest-provenance.yml +2 -2
- package/.github/workflows/security-gitleaks.yml +13 -4
- package/.github/workflows/security-runner-hardening.yml +2 -2
- package/.github/workflows/security-scorecard.yml +1 -1
- package/.github/workflows/security-zap-baseline.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +2 -1
- package/.github/workflows/security-zizmor.yml +1 -1
- package/.github/workflows/wiki-sync.yml +1 -1
- package/.gitleaksignore +9 -0
- package/CODE_OF_CONDUCT.md +2 -2
- package/GEMINI.md +64 -0
- package/README.md +52 -82
- package/SECURITY.md +1 -1
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +230 -58
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +145 -4
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +660 -158
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +93 -13
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +858 -15
- package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +135 -27
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +140 -12
- package/app/modules/playModule/playCommand.js +1 -1417
- package/app/modules/playModule/playCommandConstants.js +80 -0
- package/app/modules/playModule/playCommandCore.js +361 -0
- package/app/modules/playModule/playCommandHandlers.js +41 -0
- package/app/modules/playModule/playCommandMediaClient.js +1872 -0
- package/app/modules/playModule/playConfigRuntime.js +245 -4
- package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/quoteModule/quoteCommand.js +3 -2
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/statsModule/rankingCommon.js +5 -4
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/addStickerMetadata.js +4 -3
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerModule/stickerCommand.js +1 -1
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/systemMetricsModule/pingCommand.js +6 -5
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/tiktokCommand.js +2 -1
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/userModule/userCommand.js +72 -23
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/conversationRouterService.js +4 -3
- package/app/services/ai/geminiService.js +132 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/globalModuleAiHelpService.js +3 -2
- package/app/services/ai/messageCommandExecutionService.js +2 -1
- package/app/services/ai/moduleAiHelpCoreService.js +45 -14
- package/app/services/ai/moduleToolExecutorService.js +3 -2
- package/app/services/ai/moduleToolRegistryService.js +2 -1
- package/app/services/ai/toolCandidateSelectorService.js +6 -5
- package/app/services/auth/googleWebLinkService.js +3 -2
- package/app/services/auth/whatsappLoginLinkService.js +3 -2
- package/app/services/external/pokeApiService.js +4 -3
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +57 -26
- package/app/services/infra/featureFlagService.js +2 -1
- package/app/services/messaging/captchaService.js +3 -2
- package/app/services/messaging/newsBroadcastService.js +846 -29
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/services/sticker/stickerFocusService.js +11 -10
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/conversationSessionStore.js +7 -6
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/app/workers/aiLearningWorker.js +6 -5
- package/app/workers/commandConfigEnrichmentWorker.js +4 -3
- package/database/index.js +14 -8
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/docs/wiki/Home.md +1 -1
- package/ecosystem.prod.config.cjs +32 -12
- package/index.js +57 -23
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +20 -6
- package/public/apple-touch-icon.png +0 -0
- package/public/comandos/commands-catalog.json +2853 -3326
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/js/apps/apiDocsApp.js +3 -2
- package/public/js/apps/commandsReactApp.js +280 -99
- package/public/js/apps/createPackApp.js +11 -10
- package/public/js/apps/homeReactApp.js +181 -130
- package/public/js/apps/loginReactApp.js +1 -1
- package/public/js/apps/stickersApp.js +263 -110
- package/public/js/apps/termsReactApp.js +73 -24
- package/public/js/apps/userApp.js +4 -3
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +355 -280
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/api-docs.html +1 -1
- package/public/pages/aup.html +2 -2
- package/public/pages/dpa.html +3 -3
- package/public/pages/licenca.html +4 -4
- package/public/pages/login.html +1 -1
- package/public/pages/notice-and-takedown.html +2 -2
- package/public/pages/politica-de-privacidade.html +6 -6
- package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
- package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
- package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
- package/public/pages/stickers-admin.html +1 -1
- package/public/pages/stickers-create.html +1 -1
- package/public/pages/stickers.html +6 -6
- package/public/pages/suboperadores.html +2 -2
- package/public/pages/termos-de-uso-texto-integral.html +6 -6
- package/public/pages/termos-de-uso.html +3 -3
- package/public/pages/user-password-reset.html +4 -5
- package/public/pages/user-systemadm.html +9 -463
- package/public/pages/user.html +2 -2
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +11 -1
- package/scripts/email-broadcast-terms-update.mjs +2 -1
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +166 -2
- package/scripts/generate-module-agents.mjs +2 -1
- package/scripts/generate-seo-satellite-pages.mjs +5 -4
- package/scripts/github-deploy-notify.mjs +2 -1
- package/scripts/github-release-notify.mjs +25 -10
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/release.sh +2 -19
- package/scripts/security-smoketest.mjs +6 -5
- package/scripts/security-web-surface-check.mjs +218 -0
- package/scripts/sticker-catalog-loadtest.mjs +5 -4
- package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
- package/server/auth/jwt/webJwtService.js +1 -1
- package/server/auth/stickerCatalogAuthContext.js +2 -1
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
- package/server/auth/userPassword/userPasswordAuthService.js +2 -1
- package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
- package/server/auth/webAccount/webAccountHandlers.js +9 -10
- package/server/controllers/admin/adminPanelHandlers.js +267 -16
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
- package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
- package/server/controllers/sticker/stickerCatalogController.js +23 -36
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/githubController.js +3 -2
- package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/system/systemMetricsController.js +2 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +5 -3
- package/server/http/httpServer.js +11 -6
- package/server/middleware/rateLimit.js +2 -1
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/time/timeModule.js +135 -0
- package/utils/time/timeModule.test.js +65 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +7 -1
- package/public/assets/images/brand-icon-192.png +0 -0
- package/scripts/sync-readme-snapshot.mjs +0 -133
package/public/favicon-16x16.png
CHANGED
|
Binary file
|
package/public/favicon-32x32.png
CHANGED
|
Binary file
|
package/public/favicon.ico
CHANGED
|
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 =
|
|
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:
|
|
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
|
-
|
|
35
|
-
|
|
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({ ...
|
|
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-
|
|
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">
|
|
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="
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
<div className="flex
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
</
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
<
|
|
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
|
-
<
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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
|
|
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 &&
|
|
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 <=
|
|
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:
|
|
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:
|
|
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('
|
|
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 || `${
|
|
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:
|
|
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: `${
|
|
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('
|
|
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 || '
|
|
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>
|