@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
@@ -7,8 +7,7 @@ import { STICKER_PACK_ERROR_CODES, StickerPackError } from './stickerPackErrors.
7
7
  import { captureIncomingStickerAsset, resolveStickerAssetForCommand } from './stickerStorageService.js';
8
8
  import { buildStickerPackMessage, sendStickerPackWithFallback } from './stickerPackMessageService.js';
9
9
  import { sanitizeText } from './stickerPackUtils.js';
10
- import { executeQuery, TABLES } from '../../../database/index.js';
11
- import { extractSenderInfoFromMessage, extractUserIdInfo, resolveUserId } from '../../config/index.js';
10
+ import { extractSenderInfoFromMessage, extractUserIdInfo, normalizePnToJid, primeLidCache, resolveCanonicalWhatsAppJid, resolveUserId, resolveUserIdCached } from '../../config/index.js';
12
11
  import { toWhatsAppPhoneDigits } from '../../services/auth/whatsappLoginLinkService.js';
13
12
 
14
13
  /**
@@ -19,6 +18,7 @@ const RATE_MAX_ACTIONS = Math.max(1, Number(process.env.STICKER_PACK_RATE_MAX_AC
19
18
  const MAX_PACK_ITEMS = Math.max(1, Number(process.env.STICKER_PACK_MAX_ITEMS) || 30);
20
19
  const MAX_PACK_NAME_LENGTH = 120;
21
20
  const LID_SERVERS = new Set(['lid', 'hosted.lid']);
21
+ const OWNER_ID_SERVERS = new Set(['s.whatsapp.net', 'c.us', 'hosted', ...LID_SERVERS]);
22
22
 
23
23
  const rateMap = new Map();
24
24
 
@@ -457,7 +457,9 @@ const readSingleArgument = (input) => {
457
457
  };
458
458
 
459
459
  const buildOwnerLookupJids = (value) => {
460
- const normalized = normalizeJid(value) || '';
460
+ const normalizedValue = normalizeJid(value) || '';
461
+ const normalizedPn = normalizePnToJid(normalizedValue);
462
+ const normalized = normalizeJid(normalizedPn || normalizedValue) || normalizedPn || normalizedValue;
461
463
  if (!normalized || !normalized.includes('@')) return [];
462
464
  const lookup = new Set([normalized]);
463
465
  const digits = toWhatsAppPhoneDigits(normalized);
@@ -468,12 +470,39 @@ const buildOwnerLookupJids = (value) => {
468
470
  return Array.from(lookup).filter(Boolean);
469
471
  };
470
472
 
471
- const appendOwnerCandidate = (candidateSet, lookupSet, value) => {
472
- const normalized = normalizeJid(value) || '';
473
+ const appendOwnerCandidate = (candidateSet, value) => {
474
+ const normalizedValue = normalizeJid(value) || '';
475
+ const normalizedPn = normalizePnToJid(normalizedValue);
476
+ const normalized = normalizeJid(normalizedPn || normalizedValue) || normalizedPn || normalizedValue;
473
477
  if (!normalized || !normalized.includes('@')) return;
478
+ const server = getJidServer(normalized);
479
+ if (!server || !OWNER_ID_SERVERS.has(server)) return;
474
480
  candidateSet.add(normalized);
475
481
  for (const lookupJid of buildOwnerLookupJids(normalized)) {
476
- lookupSet.add(lookupJid);
482
+ candidateSet.add(lookupJid);
483
+ }
484
+ };
485
+
486
+ const appendOwnerCandidatesFromSource = (candidateSet, source) => {
487
+ if (!source) return;
488
+
489
+ const info = extractUserIdInfo(source);
490
+ appendOwnerCandidate(candidateSet, resolveUserIdCached(info));
491
+ appendOwnerCandidate(candidateSet, info.jid);
492
+ appendOwnerCandidate(candidateSet, info.lid);
493
+ appendOwnerCandidate(candidateSet, info.participantAlt);
494
+ appendOwnerCandidate(candidateSet, info.raw);
495
+
496
+ if (typeof source === 'object') {
497
+ appendOwnerCandidate(candidateSet, source.id);
498
+ appendOwnerCandidate(candidateSet, source.jid);
499
+ appendOwnerCandidate(candidateSet, source.lid);
500
+ appendOwnerCandidate(candidateSet, source.participant);
501
+ appendOwnerCandidate(candidateSet, source.participantAlt);
502
+ appendOwnerCandidate(candidateSet, source.remoteJid);
503
+ appendOwnerCandidate(candidateSet, source.remoteJidAlt);
504
+ } else {
505
+ appendOwnerCandidate(candidateSet, source);
477
506
  }
478
507
  };
479
508
 
@@ -505,58 +534,42 @@ const dedupePacksById = (packs = []) => {
505
534
 
506
535
  const resolveOwnerCandidatesForPackCommand = async ({ senderJid, messageInfo }) => {
507
536
  const candidates = new Set();
508
- const lookupByJid = new Set();
509
537
 
510
538
  const senderInfo = extractSenderInfoFromMessage(messageInfo);
511
- appendOwnerCandidate(candidates, lookupByJid, senderJid);
512
- appendOwnerCandidate(candidates, lookupByJid, senderInfo?.jid);
513
- appendOwnerCandidate(candidates, lookupByJid, senderInfo?.participantAlt);
514
- appendOwnerCandidate(candidates, lookupByJid, senderInfo?.lid);
515
-
516
- const directResolved = await resolveUserId(extractUserIdInfo(senderJid)).catch(() => null);
517
- if (directResolved) {
518
- appendOwnerCandidate(candidates, lookupByJid, directResolved);
519
- }
520
-
521
- const senderResolved = await resolveUserId({
522
- lid: senderInfo?.lid,
539
+ appendOwnerCandidatesFromSource(candidates, senderJid);
540
+ appendOwnerCandidatesFromSource(candidates, senderInfo);
541
+ appendOwnerCandidatesFromSource(candidates, messageInfo?.key);
542
+ appendOwnerCandidatesFromSource(candidates, {
523
543
  jid: senderInfo?.jid || senderJid || null,
544
+ lid: senderInfo?.lid || null,
524
545
  participantAlt: senderInfo?.participantAlt || null,
525
- }).catch(() => null);
526
- if (senderResolved) {
527
- appendOwnerCandidate(candidates, lookupByJid, senderResolved);
528
- }
546
+ remoteJid: senderInfo?.remoteJid || null,
547
+ remoteJidAlt: senderInfo?.remoteJidAlt || null,
548
+ });
529
549
 
530
- const lookupValues = Array.from(lookupByJid).filter(Boolean);
531
- for (let offset = 0; offset < lookupValues.length; offset += 200) {
532
- const chunk = lookupValues.slice(offset, offset + 200);
533
- if (!chunk.length) continue;
534
- const placeholders = chunk.map(() => '?').join(', ');
535
- const lookupParams = [...chunk, ...chunk];
536
- const rows = await executeQuery(
537
- `SELECT lid, jid
538
- FROM ${TABLES.LID_MAP}
539
- WHERE jid IN (${placeholders})
540
- OR lid IN (${placeholders})
541
- ORDER BY last_seen DESC
542
- LIMIT 500`,
543
- lookupParams,
544
- ).catch(() => []);
545
-
546
- for (const row of Array.isArray(rows) ? rows : []) {
547
- appendOwnerCandidate(candidates, lookupByJid, row?.jid || '');
548
- appendOwnerCandidate(candidates, lookupByJid, row?.lid || '');
549
- }
550
+ const lidCandidates = Array.from(candidates).filter((candidate) => LID_SERVERS.has(getJidServer(candidate)));
551
+ if (lidCandidates.length) {
552
+ await primeLidCache(lidCandidates).catch(() => null);
550
553
  }
551
554
 
552
- const lidCandidates = Array.from(candidates).filter((candidate) => LID_SERVERS.has(getJidServer(candidate)));
553
- for (const lidValue of lidCandidates) {
554
- const resolved = await resolveUserId(extractUserIdInfo(lidValue)).catch(() => null);
555
- if (resolved) {
556
- appendOwnerCandidate(candidates, lookupByJid, resolved);
557
- }
555
+ const currentCandidates = Array.from(candidates);
556
+ const resolvedCandidates = await Promise.all(
557
+ currentCandidates.map(async (candidate) => {
558
+ const info = extractUserIdInfo(candidate);
559
+ const resolvedCached = resolveUserIdCached(info);
560
+ const resolved = await resolveUserId(info).catch(() => null);
561
+ return [resolvedCached, resolved];
562
+ }),
563
+ );
564
+
565
+ for (const [resolvedCached, resolved] of resolvedCandidates) {
566
+ appendOwnerCandidate(candidates, resolvedCached);
567
+ appendOwnerCandidate(candidates, resolved);
558
568
  }
559
569
 
570
+ const canonicalWhatsApp = resolveCanonicalWhatsAppJid(...Array.from(candidates));
571
+ appendOwnerCandidate(candidates, canonicalWhatsApp);
572
+
560
573
  return Array.from(candidates);
561
574
  };
562
575
 
@@ -712,7 +725,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
712
725
  const name = normalizePackName(base);
713
726
  const publisher = options.publisher || options.pub || options.autor || senderName || 'OmniZap';
714
727
  const description = options.desc || options.description || '';
715
- const visibility = options.visibility || options.vis || 'public';
728
+ const visibility = options.visibility || options.vis || 'private';
716
729
 
717
730
  const created = await stickerPackService.createPack({
718
731
  ownerJid,
@@ -1121,16 +1134,24 @@ export async function maybeCaptureIncomingSticker({ messageInfo, senderJid, isMe
1121
1134
  if (!isUserJid(senderJid)) return null;
1122
1135
 
1123
1136
  const senderInfo = extractSenderInfoFromMessage(messageInfo);
1124
- let ownerJid = normalizeJid(senderJid) || senderJid;
1137
+ const senderIdentity = extractUserIdInfo({
1138
+ lid: senderInfo?.lid || null,
1139
+ jid: senderInfo?.jid || senderJid || null,
1140
+ participantAlt: senderInfo?.participantAlt || null,
1141
+ remoteJid: senderInfo?.remoteJid || null,
1142
+ remoteJidAlt: senderInfo?.remoteJidAlt || null,
1143
+ });
1144
+
1145
+ const cachedOwner = resolveUserIdCached(senderIdentity);
1146
+ let ownerJid = normalizeJid(cachedOwner || senderIdentity.jid || senderIdentity.lid || senderJid) || senderJid;
1125
1147
  try {
1126
- const resolvedOwner = await resolveUserId({
1127
- lid: senderInfo?.lid,
1128
- jid: senderInfo?.jid || senderJid || null,
1129
- participantAlt: senderInfo?.participantAlt || null,
1130
- });
1148
+ if (senderIdentity.lid) {
1149
+ await primeLidCache([senderIdentity.lid]).catch(() => null);
1150
+ }
1151
+ const resolvedOwner = await resolveUserId(senderIdentity);
1131
1152
  ownerJid = normalizeJid(resolvedOwner || ownerJid) || ownerJid;
1132
1153
  } catch {
1133
- ownerJid = normalizeJid(senderJid) || senderJid;
1154
+ ownerJid = normalizeJid(cachedOwner || senderJid) || senderJid;
1134
1155
  }
1135
1156
 
1136
1157
  try {
@@ -331,7 +331,7 @@ export function createStickerPackService(options = {}) {
331
331
  };
332
332
  };
333
333
 
334
- const sanitizeMetadata = ({ name, publisher, description, visibility }) => {
334
+ const sanitizeMetadata = ({ name, publisher, description, visibility, defaultVisibility = 'private' }) => {
335
335
  const normalizedName = sanitizeText(name, MAX_NAME_LENGTH, { allowEmpty: false });
336
336
  const normalizedPublisher = sanitizeText(publisher, MAX_PUBLISHER_LENGTH, {
337
337
  allowEmpty: false,
@@ -339,7 +339,7 @@ export function createStickerPackService(options = {}) {
339
339
  const normalizedDescription = sanitizeText(description, MAX_DESCRIPTION_LENGTH, {
340
340
  allowEmpty: true,
341
341
  });
342
- const normalizedVisibility = toVisibility(visibility, 'public');
342
+ const normalizedVisibility = toVisibility(visibility, defaultVisibility);
343
343
 
344
344
  ensureValue(normalizedName, STICKER_PACK_ERROR_CODES.INVALID_INPUT, 'Nome do pack é obrigatório.');
345
345
  ensureValue(normalizedPublisher, STICKER_PACK_ERROR_CODES.INVALID_INPUT, 'Publisher do pack é obrigatório.');
@@ -352,13 +352,20 @@ export function createStickerPackService(options = {}) {
352
352
  };
353
353
  };
354
354
 
355
- const createPack = async ({ ownerJid, name, publisher, description, visibility = 'public', status = 'published', packStatus = undefined, packThemeKey = undefined, packVolume = undefined, isAutoPack = undefined, lastRebalancedAt = undefined }) => {
355
+ const createPack = async ({ ownerJid, name, publisher, description, visibility = undefined, status = 'published', packStatus = undefined, packThemeKey = undefined, packVolume = undefined, isAutoPack = undefined, lastRebalancedAt = undefined }) => {
356
356
  const owner = resolveOwner(ownerJid);
357
+ const isAutoPackEnabled = isAutoPack === true || Number(isAutoPack || 0) === 1;
357
358
  const normalizedStatus = PACK_STATUS_VALUES.has(String(status || '').toLowerCase()) ? String(status).toLowerCase() : 'published';
358
359
 
359
360
  return runAction('create_pack', { owner_jid: owner }, async () => {
360
361
  return runInTransaction(async (connection) => {
361
- const metadata = sanitizeMetadata({ name, publisher, description, visibility });
362
+ const metadata = sanitizeMetadata({
363
+ name,
364
+ publisher,
365
+ description,
366
+ visibility,
367
+ defaultVisibility: isAutoPackEnabled ? 'public' : 'private',
368
+ });
362
369
  if (hasOwnerPackLimit) {
363
370
  const existing = await deps.packRepository.listStickerPacksByOwner(owner, {
364
371
  limit: maxPacksPerOwner + 1,
@@ -384,7 +391,7 @@ export function createStickerPackService(options = {}) {
384
391
  pack_status: packStatus,
385
392
  pack_theme_key: packThemeKey,
386
393
  pack_volume: packVolume,
387
- is_auto_pack: isAutoPack,
394
+ is_auto_pack: isAutoPackEnabled,
388
395
  last_rebalanced_at: lastRebalancedAt,
389
396
  version: 1,
390
397
  },
@@ -679,7 +686,7 @@ export function createStickerPackService(options = {}) {
679
686
  description: source.description,
680
687
  pack_key: packKey,
681
688
  cover_sticker_id: source.cover_sticker_id,
682
- visibility: 'public',
689
+ visibility: 'private',
683
690
  version: 1,
684
691
  },
685
692
  connection,
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/systemMetricsModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -335,6 +335,35 @@
335
335
  "schema": "legacy_v1_and_v2",
336
336
  "legacy_name": "statusbot",
337
337
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
338
+ },
339
+ "user_experience": {
340
+ "resumo_usuario": "Exibe latência e estado de saúde do servidor com um comando simples. Não requer Premium.",
341
+ "quando_usar": ["Antes de iniciar tarefas importantes, para confirmar se o servidor está respondendo.", "Após perceber lentidão ou instabilidade, para checar o status rapidamente.", "Durante monitoramento rápido para verificar se tudo está estável ao longo do dia."],
342
+ "exemplos_reais": [
343
+ {
344
+ "situacao": "Checagem rápida antes de iniciar uma tarefa.",
345
+ "comando": "<prefix>statusbot",
346
+ "resposta_esperada": "Latência atual: 42 ms | Status: OK.",
347
+ "variacao": "ou <prefix>ping."
348
+ },
349
+ {
350
+ "situacao": "Lentidão percebida durante pico de tráfego.",
351
+ "comando": "<prefix>statusbot",
352
+ "resposta_esperada": "Latência atual: 320 ms | Status: Atenção - possíveis lentidões. Verifique sua rede.",
353
+ "variacao": "Se o problema persistir, tente novamente em alguns minutos."
354
+ },
355
+ {
356
+ "situacao": "Verificando disponibilidade após manutenção.",
357
+ "comando": "<prefix>statusbot",
358
+ "resposta_esperada": "Latência atual: 15 ms | Status: OK.",
359
+ "variacao": "Se retornar erro, espere e tente novamente."
360
+ }
361
+ ],
362
+ "resposta_esperada": ["Latência atual: <valor> ms | Status: OK.", "Latência atual: <valor> ms | Status: Atenção - verifique rede.", "Latência atual: <valor> ms | Status: ERRO - serviço indisponível."],
363
+ "erros_comuns_usuario": ["Esquecer de incluir o prefixo <prefix> ao digitar o comando.", "Executar sem estar conectado à internet ou com a rede instável.", "Esperar uma resposta com muitos detalhes além da latência e do status simples.", "Não estar logado com Google quando a autenticação for necessária.", "Tentar usar o comando em horários de manutenção sem observar a latência."],
364
+ "passos_se_der_erro": ["Verifique a sua conexão com a internet e tente novamente.", "Aguarde alguns segundos e execute novamente o comando: <prefix>statusbot.", "Confira se há mensagens de erro específicas (ex.: permissionError) e corrija as permissões se necessário.", "Se o problema persistir, tente em outro momento ou contate o suporte, descrevendo o que aconteceu."],
365
+ "resumo_usuario_origem": "auto_ia_assistida",
366
+ "resumo_usuario_revisao_pendente": true
338
367
  }
339
368
  }
340
369
  ],
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/tiktokModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -357,6 +357,35 @@
357
357
  "schema": "legacy_v1_and_v2",
358
358
  "legacy_name": "baixartiktok",
359
359
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
360
+ },
361
+ "user_experience": {
362
+ "resumo_usuario": "Baixe vídeos do TikTok sem marca d'água a partir de URLs, direto no chat.",
363
+ "quando_usar": ["Quero salvar vídeos do TikTok sem a marca d’água para assistir offline.", "Preciso baixar até 5 vídeos de uma vez.", "Uso rápido: baixar rapidamente sem complicações."],
364
+ "exemplos_reais": [
365
+ {
366
+ "situacao": "Baixar um único vídeo.",
367
+ "comando": "<prefix>baixartiktok https://www.tiktok.com/@usuario/video/12345",
368
+ "resposta_esperada": "Comando executado com sucesso.",
369
+ "variacao": "<prefix>tt https://tiktok.com/@usuario/video/12345."
370
+ },
371
+ {
372
+ "situacao": "Baixar até 5 vídeos de uma vez.",
373
+ "comando": "<prefix>tt https://www.tiktok.com/@a/video/1 https://www.tiktok.com/@b/video/2",
374
+ "resposta_esperada": "Comando executado com sucesso.",
375
+ "variacao": "<prefix>baixartiktok https://tiktok.com/@a/video/1 https://tiktok.com/@b/video/2."
376
+ },
377
+ {
378
+ "situacao": "Formato de uso inválido.",
379
+ "comando": "<prefix>baixartiktok",
380
+ "resposta_esperada": "Formato de uso inválido. Consulte metodos_de_uso.",
381
+ "variacao": "<prefix>tt <url> <url> extra."
382
+ }
383
+ ],
384
+ "resposta_esperada": ["Comando executado com sucesso.", "Formato de uso inválido. Consulte metodos_de_uso.", "Permissão insuficiente para executar este comando."],
385
+ "erros_comuns_usuario": ["Não incluir URL(s) ou incluir mais de 5 URLs.", "Usar URLs que não são do TikTok.", "Esquecer de colocar o prefixo correto do comando.", "Tentar usar sem conexão estável."],
386
+ "passos_se_der_erro": ["Confira se inseriu entre 1 e 5 URLs válidas do TikTok.", "Use o formato correto: <prefix>baixartiktok <url> ou <prefix>tt <url1> <url2> ...", "Verifique a sua conexão com a internet.", "Se o erro persistir, tente novamente mais tarde ou contate o suporte."],
387
+ "resumo_usuario_origem": "auto_ia_assistida",
388
+ "resumo_usuario_revisao_pendente": true
360
389
  }
361
390
  }
362
391
  ],
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/userModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -377,6 +377,35 @@
377
377
  "schema": "legacy_v1_and_v2",
378
378
  "legacy_name": "perfil",
379
379
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
380
+ },
381
+ "user_experience": {
382
+ "resumo_usuario": "Consulta o perfil e estatísticas de um usuário. Exibe dados básicos como nome, bio, foto e métricas rápidas.",
383
+ "quando_usar": ["Precisa ver informações de alguém no chat.", "Quer confirmar dados de um usuário pelo id, telefone ou menção.", "Antes de agir com base no perfil, verifique as informações obtidas."],
384
+ "exemplos_reais": [
385
+ {
386
+ "situacao": "Ver o próprio perfil.",
387
+ "comando": "<prefix>perfil perfil",
388
+ "resposta_esperada": "Perfil exibido com dados básicos do seu usuário.",
389
+ "variacao": "perfil."
390
+ },
391
+ {
392
+ "situacao": "Consultar perfil por ID.",
393
+ "comando": "<prefix>perfil perfil 12345",
394
+ "resposta_esperada": "Perfil do usuário 12345 exibido.",
395
+ "variacao": "<prefix>perfil perfil 12345."
396
+ },
397
+ {
398
+ "situacao": "Consultar perfil por @contato.",
399
+ "comando": "<prefix>usuario perfil @joana",
400
+ "resposta_esperada": "Perfil do contato exibido.",
401
+ "variacao": "<prefix>usuario perfil @joana."
402
+ }
403
+ ],
404
+ "resposta_esperada": ["Perfil exibido com sucesso com informações básicas e estatísticas.", "Erro: usuário não encontrado ou alvo inválido."],
405
+ "erros_comuns_usuario": ["Formato de uso inválido. Use <prefix>perfil perfil [alvo].", "Alvo ausente ou inválido (id, telefone ou menção).", "Não autorizado: verifique se está logado com sua conta Google."],
406
+ "passos_se_der_erro": ["Conferir formato do comando: <prefix>perfil perfil [alvo].", "Verificar o alvo informado (id, telefone ou menção).", "Garantir login com conta Google.", "Se o erro persistir, tente novamente mais tarde ou contate o suporte com o comando utilizado."],
407
+ "resumo_usuario_origem": "auto_ia_assistida",
408
+ "resumo_usuario_revisao_pendente": true
380
409
  }
381
410
  }
382
411
  ],
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/waifuPicsModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -90,9 +90,9 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
90
90
  - <prefix>wp neko
91
91
  - mensagens_uso (variantes):
92
92
  - default:
93
- - 💡 _Uso:_ <prefix>waifu <categoria>
94
- Exemplo: <prefix>waifu neko
95
- - Dica: Use <prefix>waifuajuda para ver todas as categorias! 🎨
93
+ - 🖼️ _Como usar:_ <prefix>waifu <categoria>
94
+ - Exemplos rápidos: <prefix>waifu neko | <prefix>wp hug
95
+ - Quer ver todas as categorias disponíveis? Use <prefix>waifuajuda.
96
96
  - subcomandos:
97
97
  - (nenhum)
98
98
  - argumentos:
@@ -125,12 +125,22 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
125
125
  - consulta API externa
126
126
  - envia imagem no chat
127
127
  - respostas_padrao:
128
- - success: Prontinho! Aqui está sua imagem.
129
- - usage_error: Ops! Parece que você esqueceu a categoria. Use <prefix>waifuajuda para ver as opções disponíveis. 🧐
130
- - permission_error: Eita! Você não tem permissão para usar este comando. Entre em contato com um administrador. 🔐
131
- - sucesso: Comando executado com sucesso.
132
- - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
133
- - erro_permissao: Permissão insuficiente para executar este comando.
128
+ - success: ✅ Pedido recebido! Aqui vai sua imagem.
129
+ Dica: você pode pedir outra categoria no próximo comando (ex.: <prefix>waifu neko).
130
+ - usage_error: Não entendi o formato do comando.
131
+ Exemplos:
132
+ <prefix>waifu neko
133
+ <prefix>waifunsfw waifu
134
+ Para ver todas as categorias: <prefix>waifuajuda
135
+ - permission_error: 🔒 Este comando não está liberado para você neste contexto.
136
+ Se for NSFW em grupo, peça para um admin usar <prefix>nsfw on.
137
+ - sucesso: ✅ Imagem enviada com sucesso!
138
+ Exemplo de próximo pedido: <prefix>waifu hug
139
+ - erro_uso: ❗ Categoria inválida ou ausente.
140
+ Exemplos: <prefix>waifu neko | <prefix>wp waifu
141
+ Veja a lista completa em <prefix>waifuajuda.
142
+ - erro_permissao: 🔒 Não consegui liberar este pedido para seu perfil.
143
+ Se achar que é engano, verifique seu plano e tente novamente.
134
144
  - mensagens_sistema:
135
145
  - (nao informado)
136
146
  - limites_operacionais:
@@ -211,9 +221,9 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
211
221
  - <prefix>wpnsfw waifu
212
222
  - mensagens_uso (variantes):
213
223
  - default:
214
- - 🔞 _Uso:_ <prefix>waifunsfw <categoria>
215
- Exemplo: <prefix>wpnsfw blowjob
216
- - Atenção: O grupo deve estar com NSFW ligado!
224
+ - 🔞 _Como usar:_ <prefix>waifunsfw <categoria>
225
+ - Exemplos rápidos: <prefix>waifunsfw waifu | <prefix>wpnsfw neko
226
+ - Pré-requisitos: plano Premium; em grupo, NSFW ativo com <prefix>nsfw on.
217
227
  - subcomandos:
218
228
  - (nenhum)
219
229
  - argumentos:
@@ -247,12 +257,22 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
247
257
  - consulta API externa
248
258
  - envia imagem NSFW no chat
249
259
  - respostas_padrao:
250
- - success: Prontinho! Aqui está sua imagem.
251
- - usage_error: Ops! Parece que você esqueceu a categoria. Use <prefix>waifuajuda para ver as opções disponíveis. 🧐
252
- - permission_error: Eita! Você não tem permissão para usar este comando. Entre em contato com um administrador. 🔐
253
- - sucesso: Comando executado com sucesso.
254
- - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
255
- - erro_permissao: Permissão insuficiente para executar este comando.
260
+ - success: ✅ Pedido recebido! Aqui vai sua imagem.
261
+ Dica: você pode pedir outra categoria no próximo comando (ex.: <prefix>waifu neko).
262
+ - usage_error: Não entendi o formato do comando.
263
+ Exemplos:
264
+ <prefix>waifu neko
265
+ <prefix>waifunsfw waifu
266
+ Para ver todas as categorias: <prefix>waifuajuda
267
+ - permission_error: 🔒 Este comando não está liberado para você neste contexto.
268
+ Se for NSFW em grupo, peça para um admin usar <prefix>nsfw on.
269
+ - sucesso: 🔞 Imagem NSFW enviada.
270
+ Exemplo de próximo pedido: <prefix>waifunsfw neko
271
+ - erro_uso: ❗ Categoria NSFW inválida ou ausente.
272
+ Exemplos: <prefix>waifunsfw waifu | <prefix>wpnsfw neko
273
+ Veja opções em <prefix>waifuajuda.
274
+ - erro_permissao: 🔒 Este comando NSFW exige acesso Premium.
275
+ Em grupos, também é preciso NSFW ativo com <prefix>nsfw on.
256
276
  - mensagens_sistema:
257
277
  - (nao informado)
258
278
  - limites_operacionais:
@@ -332,8 +352,9 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
332
352
  - <prefix>waifuajuda
333
353
  - mensagens_uso (variantes):
334
354
  - default:
335
- - 📖 _Guia Rápido:_ Digite <prefix>waifuajuda para ver as categorias SFW e NSFW disponíveis.
336
- - Use <prefix>waifu <categoria> para receber uma imagem!
355
+ - 📖 _Como usar:_ <prefix>waifuajuda
356
+ - Depois do guia, teste: <prefix>waifu neko
357
+ - Para NSFW: <prefix>waifunsfw waifu (Premium; em grupo exige <prefix>nsfw on).
337
358
  - subcomandos:
338
359
  - (nenhum)
339
360
  - argumentos:
@@ -364,12 +385,21 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
364
385
  - efeitos_colaterais:
365
386
  - envia mensagem de ajuda
366
387
  - respostas_padrao:
367
- - success: Prontinho! Aqui está sua imagem.
368
- - usage_error: Ops! Parece que você esqueceu a categoria. Use <prefix>waifuajuda para ver as opções disponíveis. 🧐
369
- - permission_error: Eita! Você não tem permissão para usar este comando. Entre em contato com um administrador. 🔐
370
- - sucesso: Comando executado com sucesso.
371
- - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
372
- - erro_permissao: Permissão insuficiente para executar este comando.
388
+ - success: ✅ Pedido recebido! Aqui vai sua imagem.
389
+ Dica: você pode pedir outra categoria no próximo comando (ex.: <prefix>waifu neko).
390
+ - usage_error: Não entendi o formato do comando.
391
+ Exemplos:
392
+ <prefix>waifu neko
393
+ <prefix>waifunsfw waifu
394
+ Para ver todas as categorias: <prefix>waifuajuda
395
+ - permission_error: 🔒 Este comando não está liberado para você neste contexto.
396
+ Se for NSFW em grupo, peça para um admin usar <prefix>nsfw on.
397
+ - sucesso: 📚 Guia enviado com sucesso.
398
+ Agora experimente: <prefix>waifu neko
399
+ - erro_uso: ℹ️ Este comando não precisa de argumentos.
400
+ Use apenas: <prefix>waifuajuda
401
+ - erro_permissao: 🔒 Não consegui mostrar o guia neste contexto.
402
+ Tente novamente no privado ou em um grupo permitido.
373
403
  - mensagens_sistema:
374
404
  - (nao informado)
375
405
  - limites_operacionais:
@@ -357,6 +357,35 @@
357
357
  "schema": "legacy_v1_and_v2",
358
358
  "legacy_name": "waifu",
359
359
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
360
+ },
361
+ "user_experience": {
362
+ "resumo_usuario": "Guia rápido para usar o comando waifu e receber uma imagem de anime (SFW) da categoria escolhida.",
363
+ "quando_usar": ["Quando você quer uma imagem de anime específica (ex.: neko, waifu) sem enviar outras perguntas."],
364
+ "exemplos_reais": [
365
+ {
366
+ "situacao": "Quero uma imagem de neko.",
367
+ "comando": "<prefix>waifu neko",
368
+ "resposta_esperada": "✅ Imagem enviada com sucesso! Exemplo de próximo pedido: <prefix>waifu hug.",
369
+ "variacao": "Usando alias: <prefix>wp neko."
370
+ },
371
+ {
372
+ "situacao": "Não informei a categoria.",
373
+ "comando": "<prefix>waifu",
374
+ "resposta_esperada": "❗ Categoria inválida ou ausente. Exemplos: <prefix>waifu neko | <prefix>wp waifu Veja a lista completa em <prefix>waifuajuda.",
375
+ "variacao": "Tente: <prefix>waifu neko."
376
+ },
377
+ {
378
+ "situacao": "Categoria não suportada.",
379
+ "comando": "<prefix>waifu dragon",
380
+ "resposta_esperada": "❗ Categoria inválida ou ausente. Exemplos: <prefix>waifu neko | <prefix>wp waifu Veja a lista completa em <prefix>waifuajuda.",
381
+ "variacao": "Tente uma categoria comum como neko ou waifu."
382
+ }
383
+ ],
384
+ "resposta_esperada": ["O bot envia uma imagem de anime da categoria solicitada (SFW)."],
385
+ "erros_comuns_usuario": ["Esquecer de indicar a categoria", "Usar uma categoria não suportada", "Usar o comando sem o prefixo quando necessário", "Erro de conexão temporário"],
386
+ "passos_se_der_erro": ["1. Verifique se digitou a categoria corretamente. 2. Use o formato com prefixo: <prefix>waifu <categoria> ou <prefix>wp <categoria>. 3. Se receber erro de categoria, peça a lista de categorias com <prefix>waifuajuda e es"],
387
+ "resumo_usuario_origem": "auto_ia_assistida",
388
+ "resumo_usuario_revisao_pendente": true
360
389
  }
361
390
  },
362
391
  {
@@ -575,6 +604,35 @@
575
604
  "schema": "legacy_v1_and_v2",
576
605
  "legacy_name": "waifunsfw",
577
606
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
607
+ },
608
+ "user_experience": {
609
+ "resumo_usuario": "Envie imagens NSFW de waifus em grupos autorizados. Requer Premium e NSFW ativo. Use <prefix>waifunsfw <categoria> ou <prefix>wpnsfw <waifu>.",
610
+ "quando_usar": ["Quando o grupo tiver NSFW ativo e você for assinante Premium.", "Para solicitar uma imagem NSFW de uma categoria válida (ex.: neko, waifu, etc.).", "Para confirmar qual variedade de conteúdo NSFW está disponível no momento."],
611
+ "exemplos_reais": [
612
+ {
613
+ "situacao": "Grupo com NSFW ativo e usuário Premium solicita neko.",
614
+ "comando": "<prefix>waifunsfw neko",
615
+ "resposta_esperada": "🔞 Imagem NSFW enviada. Exemplo de próximo pedido: <prefix>waifunsfw neko.",
616
+ "variacao": "neko."
617
+ },
618
+ {
619
+ "situacao": "Grupo sem Premium ou NSFW ativo.",
620
+ "comando": "<prefix>waifunsfw neko",
621
+ "resposta_esperada": "🔒 Este comando NSFW exige acesso Premium. Em grupos, também é preciso NSFW ativo com <prefix>nsfw on.",
622
+ "variacao": "premium_required."
623
+ },
624
+ {
625
+ "situacao": "Categoria NSFW inválida.",
626
+ "comando": "<prefix>waifunsfw manga",
627
+ "resposta_esperada": "❗ Categoria NSFW inválida ou ausente. Exemplos: <prefix>waifunsfw waifu | <prefix>wpnsfw neko Veja opções em <prefix>waifuajuda.",
628
+ "variacao": "categoria_invalida."
629
+ }
630
+ ],
631
+ "resposta_esperada": ["🔞 Imagem NSFW enviada. Exemplo de próximo pedido: <prefix>waifunsfw neko", "❗ Categoria NSFW inválida ou ausente. Exemplos: <prefix>waifunsfw waifu | <prefix>wpnsfw neko Veja opções em <prefix>waifuajuda.", "🔒 Este comando NSFW exige acesso Premium. Em grupos, também é preciso NSFW ativo com <prefix>nsfw on."],
632
+ "erros_comuns_usuario": ["Não informar a categoria NSFW", "Categoria informada não é suportada", "NSFW não está ativo no grupo", "Usuário não possui assinatura Premium"],
633
+ "passos_se_der_erro": ["Verifique se o NSFW está ativo no grupo com <prefix>nsfw on e peça ao admin para ativar, se necessário.", "Confirme que você possui uma assinatura Premium válida para usar o comando.", "Certifique-se de digitar uma categoria NSFW suportada, por exemplo neko, waifu, etc.", "Tente novamente com uma categoria diferente ou em outro momento; se o problema persistir, peça ajuda ao administrador do grupo."],
634
+ "resumo_usuario_origem": "auto_ia_assistida",
635
+ "resumo_usuario_revisao_pendente": true
578
636
  }
579
637
  },
580
638
  {
@@ -771,6 +829,35 @@
771
829
  "schema": "legacy_v1_and_v2",
772
830
  "legacy_name": "waifuajuda",
773
831
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
832
+ },
833
+ "user_experience": {
834
+ "resumo_usuario": "Guia rápido das categorias de fotos anime que posso enviar. Mostra todas as opções disponíveis e como usar o comando. Não é necessário Premium; funciona para planos comum e premium.",
835
+ "quando_usar": ["Quando você quer conhecer todas as categorias de fotos disponíveis sem digitar argumentos", "Quando precisa confirmar que o comando não aceita parâmetros", "Quando desejar usar o alias wppicshelp para abrir o guia rapidamente"],
836
+ "exemplos_reais": [
837
+ {
838
+ "situacao": "Usuário quer abrir o guia rapidamente com o prefix.",
839
+ "comando": "<prefix>waifuajuda",
840
+ "resposta_esperada": "Guia de categorias exibido. Exemplo: <prefix>waifu neko.",
841
+ "variacao": "uso direto com <prefix>."
842
+ },
843
+ {
844
+ "situacao": "Usuário prefere usar o alias.",
845
+ "comando": "wppicshelp",
846
+ "resposta_esperada": "Guia de categorias exibido. Observação: você pode usar <prefix>waifu neko para abrir uma categoria específica.",
847
+ "variacao": "alias."
848
+ },
849
+ {
850
+ "situacao": "Usuário está em contexto privado ou grupo permitido.",
851
+ "comando": "<prefix>waifuajuda",
852
+ "resposta_esperada": "Guia pronto. Veja as categorias disponíveis e escolha uma: neko, shinobu, etc.",
853
+ "variacao": "contexto privado ou grupo permitido."
854
+ }
855
+ ],
856
+ "resposta_esperada": ["Guia de categorias exibido com sucesso. Use <prefix>waifu neko para ver fotos de uma categoria específica."],
857
+ "erros_comuns_usuario": ["Tentar usar o comando com argumentos, quando ele não exige nenhum.", "Esquecer de incluir o prefixo, por exemplo usar 'waifuajuda' sem o prefixo.", "Tentar usar em contexto onde o guia não pode ser exibido (contextos não suportados)."],
858
+ "passos_se_der_erro": ["Verifique se o comando está sendo usado em um contexto permitido (privado ou grupo permitido).", "Tente novamente com o prefix correto: <prefix>waifuajuda.", "Se o guia não aparecer, tente novamente mais tarde ou entre em contato com o suporte."],
859
+ "resumo_usuario_origem": "auto_ia_assistida",
860
+ "resumo_usuario_revisao_pendente": true
774
861
  }
775
862
  }
776
863
  ],