sapiens-mcp 1.59.0 → 1.61.0

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/dist/registry.js CHANGED
@@ -35,6 +35,7 @@ import { publicidade, publicidadeSchema } from "./tools/publicidade.js";
35
35
  import { reference, referenceSchema } from "./tools/reference.js";
36
36
  import { trilhas, trilhasSchema } from "./tools/trilhas.js";
37
37
  import { semana, semanaSchema } from "./tools/semana.js";
38
+ import { distribution, distributionSchema } from "./tools/distribution.js";
38
39
  import { shareDrop, shareDropSchema } from "./tools/shareDrop.js";
39
40
  import { skill, skillSchema } from "./tools/skill.js";
40
41
  import { resume, resumeSchema } from "./tools/resume.js";
@@ -144,7 +145,7 @@ export const TOOLS = {
144
145
  handler: brand,
145
146
  },
146
147
  sapiens_character: {
147
- description: "Personagens (character sheets) do Sapiens — a tabela `influencers`: personagem reutilizável com imagens (pra character-lock em geração) + alma (systemPrompt), tudo amarrado à conta do dono do token (sem admin). Sub-actions: list_public (catálogo global de personagens públicos do Explorar; cada um traz mainImageUrl/imageUrls usáveis direto como referenceImageUrls em sapiens_image; sem custo, sem login), get (detalhe de 1 por characterId — público+ativo qualquer um vê, draft/privado só o dono; systemPrompt só volta pro dono), list_mine (os personagens do próprio user, inclui drafts/privados), create (cria rascunho na conta: name + gender + opcional form/title/systemPrompt), add_image (adiciona imagem ao próprio personagem via imageUrl público OU sourceImageId da galeria; 1ª vira principal), set_card (edita alma/título/lema em inglês/nome/forma do próprio), activate (publica, sai de draft, exige ≥1 imagem), set_visibility (isPublic true=Explorar+slug / false=privado). GESTÃO de imagem (por url, pegue as urls atuais em action=get campo imageUrls): remove_image (tira uma), set_main_image (define a principal), reorder_images (nova ordem via orderedUrls, posição 0=principal), e delete (apaga o personagem, permanente). FORMA (`form`, o que tipo de CORPO ele tem: human default, humanoid, animal (bicho real), creature (ser inventado), object, abstract): não é enfeite de cadastro, é o que a ficha, as figurinhas e o vídeo leem pra decidir se descrevem rosto e mãos ou silhueta e postura, e é ele que impede uma criatura de voltar desenhada como pessoa. Mande no create sempre que o personagem não for gente; personagem que já existe sem ele conserta com set_card form=creature. Ausente = human, que é o que a casa desenhava antes do campo existir. TRAÇO (`style`, em que TÉCNICA ele é feito: auto default, realista, anime, manhwa, 3d, custom): irmão da forma, e a divisão é limpa, a forma diz que CORPO é esse e o traço diz como ele é DESENHADO. As mesmas três peças leem daqui. No 'auto' a peça não afirma técnica nenhuma e as imagens de referência mandam; 'realista' é fotografia, 'anime' é cel shading com contorno de tinta, 'manhwa' é pintura de webtoon, '3d' é render com material e oclusão, 'custom' usa a linha escrita em `styleNote` (até 140 caracteres, ex: aquarela sobre papel texturizado). Mande sempre que o personagem tiver técnica definida: até ago/2026 a ficha cravava vocabulário de desenho e devolvia personagem fotográfico virado em ilustração. Conserto sem custo em quem já existe: set_card style=realista. FICHA (generate_sheet, COBRA 450 Sinapses): desenha a página-pôster do personagem no traço das imagens que ele já tem (exige pelo menos uma), em duas orientações (arg `orientation`): 'portrait' (default) é a página de processo, pose, expressões, trocas de roupa e adereços soltos na folha; 'landscape' é a prancha larga, com a volta completa à esquerda, a figura grande no meio, poses à direita, estudos de silhueta, expressão e detalhe embaixo e um painel CHARACTER ID na ponta. A personalidade sai da alma (systemPrompt) e é ela que escolhe roupa e objeto, então personagem com alma escrita rende ficha melhor. Cada geração é um estilo NOVO e elas acumulam no personagem (campo sheetUrls em action=get), nenhuma apaga a anterior, e a ficha já entra na galeria dele como referência das próximas gerações. É geração síncrona: se voltar Timeout, cheque action=get antes de repetir, senão cobra duas vezes. STICKERS (generate_stickers, COBRA 550 Sinapses): desenha 5 stickers do personagem DE UMA VEZ. Uma folha só, em 2K, com as cinco figuras separadas sobre um fundo verde chroma, recortada por código em peças 512x512 transparentes abaixo de 100KB (o teto do WhatsApp). É por isso que sai o preço de UMA imagem em 2K e não de cinco: quem paga é a folha. As peças entram no pack do personagem (um por personagem, os lotes acumulam) e já ficam no picker de expressão do dono, no chat e no Fórum. Arg `moods`: até 5 humores do vocabulário comum por slug (kkkkk, amei, isso, hmm, chega, que, aff, bora, socorro, seinao, valeu, ainao, seila, ideia, calma, contatudo, perfeito, euavisei, naovourir, zzz, somaisum, sextou, merecido, quedia, tudobem); faltando, a casa completa com os mais usados. Arg `hint`: direcionamento curto do autor (roupa, adereço, clima), até 140 caracteres. Arg `stickerTier`: 'folha' (default) é esse lote de cinco, desenhado no Gemini 3.1 Flash; 'unica' (COBRA 900 Sinapses) desenha UM sticker por vez no Gemini 3 Pro, o motor mais fiel da casa, com a figura sozinha no quadro e o dobro de pixel por peça, e leva só o PRIMEIRO mood da lista. Pra encher o pack, folha; pra traço difícil ou a reação que vira a cara do personagem, a unica. Ao oferecer a escolha, diga o NOME DO MOTOR e o que ele troca: adjetivo vago de acabamento não informa nada a quem vai pagar. Os dois caem no MESMO pack e acumulam. Sem legenda queimada na imagem, de propósito: modelo erra acento em português, então o rótulo fica na row e serve de busca no picker. Exige pelo menos uma imagem no personagem (é dela que sai a cara) e é geração síncrona: se voltar Timeout, cheque sapiens_gallery antes de repetir. Quando a resposta vem com ok=false, a folha foi gerada e paga mas o corte falhou; ela está na galeria e o recorte de novo é de graça, pela web. Publicar o pack na vitrine e o carimbo da casa (que é o que põe no picker de todo mundo) são gestos da web, não desta tool. CHARACTER VIDEO (a ficha que anda): o personagem atravessa 6 mundos em 12s, trocando de roupa em cada um, com som gerado junto, e o último plano fecha a peça com ele parando e encarando a câmera. Sai assinado com o Finalizador da casa, e o cartão de nome do fim escreve o nome do personagem com o LEMA em inglês embaixo (o campo `titleEn`, escrito uma vez em set_card): quem não tem lema recebe o subtítulo que o roteiro inventou naquele take, e ele muda no take seguinte. Exige FICHA gerada (é dela que saem a cara e o guarda-roupa), não só imagem. Duas actions, nesta ordem: plan_video (COBRA 50 Sinapses) devolve os 6 planos que a alma do personagem escolheu, com ambiente, ato, enquadramento e roupa. Cada plano vem nas duas línguas: em inglês (setting/act/wardrobe, que é o que vai pro motor) e em português (settingPt/actPt/wardrobePt). MOSTRE a versão em português pro autor, o público da casa é brasileiro e roteiro que ele lê de través não é roteiro aprovado; peça de novo quantas vezes ele quiser, porque trocar sai por 50 e o take errado sai por milhares. replan_shot (COBRA 15 Sinapses) reescreve UM plano e não toca nos outros cinco: os seis são cenas independentes, então quando o autor gosta de quatro e implica com um, troque só aquele em vez de sortear tudo de novo (mande os 6 planos em `shots`, o número em `shotIndex`, e o que ele quer diferente em `shotHint`; volta só o plano trocado, e é você que remonta o roteiro). Depois generate_video (COBRA) renderiza, com os planos aprovados no arg `shots` e o MOTOR no arg `videoTier`: 'draft' (5.400 Sinapses) é o Seedance 2.0 Mini, metade do preço, que tropeça em mão, pouca luz e câmera rápida, e 'final' (8.640 Sinapses) é o Seedance 2.0 Fast, que segura o que o Mini erra. A peça é a MESMA nos dois (mesmos 6 planos, 12s, 720p, com som), então ofereça pelo nome do motor e pelo que ele troca, nunca por adjetivo vago de acabamento. Vertical ou horizontal pelo arg `orientation`. Chamar generate_video SEM `shots` funciona, mas escreve um roteiro novo às cegas e cobra igual: não faça isso sem o autor ter visto o que vai receber. É geração síncrona e demorada: se voltar Timeout, cheque sapiens_gallery antes de repetir. Fluxo de criação: create → add_image (1+) → set_card (opcional) → activate → set_visibility isPublic=true. Pra usar um personagem público como referência numa geração, pegue mainImageUrl em list_public/get e passe em sapiens_image referenceImageUrls.",
148
+ description: "Personagens (character sheets) do Sapiens — a tabela `influencers`: personagem reutilizável com imagens (pra character-lock em geração) + alma (systemPrompt), tudo amarrado à conta do dono do token (sem admin). Sub-actions: list_public (catálogo global de personagens públicos do Explorar; cada um traz mainImageUrl/imageUrls usáveis direto como referenceImageUrls em sapiens_image; sem custo, sem login), get (detalhe de 1 por characterId — público+ativo qualquer um vê, draft/privado só o dono; systemPrompt só volta pro dono), list_mine (os personagens do próprio user, inclui drafts/privados), create (cria rascunho na conta: name + gender + opcional form/title/systemPrompt), add_image (adiciona imagem ao próprio personagem via imageUrl público OU sourceImageId da galeria; 1ª vira principal), set_card (edita alma/título/lema em inglês/nome/forma do próprio), activate (publica, sai de draft, exige ≥1 imagem), set_visibility (isPublic true=Explorar+slug / false=privado). GESTÃO de imagem (por url, pegue as urls atuais em action=get campo imageUrls): remove_image (tira uma), set_main_image (define a principal), reorder_images (nova ordem via orderedUrls, posição 0=principal), e delete (apaga o personagem, permanente). FORMA (`form`, o que tipo de CORPO ele tem: human default, humanoid, animal (bicho real), creature (ser inventado), object, abstract): não é enfeite de cadastro, é o que a ficha, as figurinhas e o vídeo leem pra decidir se descrevem rosto e mãos ou silhueta e postura, e é ele que impede uma criatura de voltar desenhada como pessoa. Mande no create sempre que o personagem não for gente; personagem que já existe sem ele conserta com set_card form=creature. Ausente = human, que é o que a casa desenhava antes do campo existir. TRAÇO (`style`, em que TÉCNICA ele é feito: auto default, realista, anime, manhwa, 3d, custom): irmão da forma, e a divisão é limpa, a forma diz que CORPO é esse e o traço diz como ele é DESENHADO. As mesmas três peças leem daqui. No 'auto' a peça não afirma técnica nenhuma e as imagens de referência mandam; 'realista' é fotografia, 'anime' é cel shading com contorno de tinta, 'manhwa' é pintura de webtoon, '3d' é render com material e oclusão, 'custom' usa a linha escrita em `styleNote` (até 140 caracteres, ex: aquarela sobre papel texturizado). Mande sempre que o personagem tiver técnica definida: até ago/2026 a ficha cravava vocabulário de desenho e devolvia personagem fotográfico virado em ilustração. Conserto sem custo em quem já existe: set_card style=realista. FICHA (generate_sheet, COBRA 450 Sinapses): desenha a página-pôster do personagem no traço das imagens que ele já tem (exige pelo menos uma), em duas orientações (arg `orientation`): 'portrait' (default) é a página de processo, pose, expressões, trocas de roupa e adereços soltos na folha; 'landscape' é a prancha larga, com a volta completa à esquerda, a figura grande no meio, poses à direita, estudos de silhueta, expressão e detalhe embaixo e um painel CHARACTER ID na ponta. A personalidade sai da alma (systemPrompt) e é ela que escolhe roupa e objeto, então personagem com alma escrita rende ficha melhor. Cada geração é um estilo NOVO e elas acumulam no personagem (campo sheetUrls em action=get), nenhuma apaga a anterior, e a ficha já entra na galeria dele como referência das próximas gerações. É geração síncrona: se voltar Timeout, cheque action=get antes de repetir, senão cobra duas vezes. STICKERS (generate_stickers, COBRA 550 Sinapses): desenha 5 stickers do personagem DE UMA VEZ. Uma folha só, em 2K, com as cinco figuras separadas sobre um fundo verde chroma, recortada por código em peças 512x512 transparentes abaixo de 100KB (o teto do WhatsApp). É por isso que sai o preço de UMA imagem em 2K e não de cinco: quem paga é a folha. As peças entram no pack do personagem (um por personagem, os lotes acumulam) e já ficam no picker de expressão do dono, no chat e no Fórum. Arg `moods`: até 5 humores do vocabulário comum por slug (kkkkk, amei, isso, hmm, chega, que, aff, bora, socorro, seinao, valeu, ainao, seila, ideia, calma, contatudo, perfeito, euavisei, naovourir, zzz, somaisum, sextou, merecido, quedia, tudobem); faltando, a casa completa com os mais usados. Arg `hint`: direcionamento curto do autor (roupa, adereço, clima), até 140 caracteres. Arg `stickerTier`: 'folha' (default) é esse lote de cinco, desenhado no Gemini 3.1 Flash; 'unica' (COBRA 900 Sinapses) desenha UM sticker por vez no Gemini 3 Pro, o motor mais fiel da casa, com a figura sozinha no quadro e o dobro de pixel por peça, e leva só o PRIMEIRO mood da lista. Pra encher o pack, folha; pra traço difícil ou a reação que vira a cara do personagem, a unica. Ao oferecer a escolha, diga o NOME DO MOTOR e o que ele troca: adjetivo vago de acabamento não informa nada a quem vai pagar. Os dois caem no MESMO pack e acumulam. Sem legenda queimada na imagem, de propósito: modelo erra acento em português, então o rótulo fica na row e serve de busca no picker. Exige pelo menos uma imagem no personagem (é dela que sai a cara) e é geração síncrona: se voltar Timeout, cheque sapiens_gallery antes de repetir. Quando a resposta vem com ok=false, a folha foi gerada e paga mas o corte falhou; ela está na galeria e o recorte de novo é de graça, pela web. Publicar o pack na vitrine e o carimbo da casa (que é o que põe no picker de todo mundo) são gestos da web, não desta tool. CHARACTER VIDEO (a ficha que anda): o personagem atravessa 6 mundos em 12s, trocando de roupa em cada um, com som gerado junto, e o último plano fecha a peça com ele parando e encarando a câmera. A peça volta FECHADA pelas duas portas (tela e agente), sem ninguém pedir: o personagem se apresenta no cartão de nome por cima do fim do último plano, com o LEMA em inglês embaixo (o campo `titleEn`, escrito uma vez em set_card), e só depois a casa assina. Quem não tem lema recebe o subtítulo que o roteiro inventou naquele take, e ele muda no take seguinte. O fecho é asset, não geração: zero Sinapse a mais, e é fail-open, então a resposta traz `closed` e `nameCard` dizendo o que entrou de verdade em vez de prometer um cartão que não está no arquivo. Pra colocar esse cartão num vídeo que JÁ existe, o caminho é a ficha do take na web (gaveta do fecho, 'Apresentação do personagem'), também sem custo. Exige FICHA gerada (é dela que saem a cara e o guarda-roupa), não só imagem. Duas actions, nesta ordem: plan_video (COBRA 50 Sinapses) devolve os 6 planos que a alma do personagem escolheu, com ambiente, ato, enquadramento e roupa. Cada plano vem nas duas línguas: em inglês (setting/act/wardrobe, que é o que vai pro motor) e em português (settingPt/actPt/wardrobePt). MOSTRE a versão em português pro autor, o público da casa é brasileiro e roteiro que ele lê de través não é roteiro aprovado; peça de novo quantas vezes ele quiser, porque trocar sai por 50 e o take errado sai por milhares. replan_shot (COBRA 15 Sinapses) reescreve UM plano e não toca nos outros cinco: os seis são cenas independentes, então quando o autor gosta de quatro e implica com um, troque só aquele em vez de sortear tudo de novo (mande os 6 planos em `shots`, o número em `shotIndex`, e o que ele quer diferente em `shotHint`; volta só o plano trocado, e é você que remonta o roteiro). Depois generate_video (COBRA) renderiza, com os planos aprovados no arg `shots` e o MOTOR no arg `videoTier`: 'draft' (5.400 Sinapses) é o Seedance 2.0 Mini, metade do preço, que tropeça em mão, pouca luz e câmera rápida, e 'final' (8.640 Sinapses) é o Seedance 2.0 Fast, que segura o que o Mini erra. A peça é a MESMA nos dois (mesmos 6 planos, 12s, 720p, com som), então ofereça pelo nome do motor e pelo que ele troca, nunca por adjetivo vago de acabamento. Vertical ou horizontal pelo arg `orientation`. Chamar generate_video SEM `shots` funciona, mas escreve um roteiro novo às cegas e cobra igual: não faça isso sem o autor ter visto o que vai receber. É geração síncrona e demorada: se voltar Timeout, cheque sapiens_gallery antes de repetir. Fluxo de criação: create → add_image (1+) → set_card (opcional) → activate → set_visibility isPublic=true. Pra usar um personagem público como referência numa geração, pegue mainImageUrl em list_public/get e passe em sapiens_image referenceImageUrls.",
148
149
  schema: characterSchema,
149
150
  handler: character,
150
151
  },
@@ -203,6 +204,11 @@ export const TOOLS = {
203
204
  schema: trilhasSchema,
204
205
  handler: trilhas,
205
206
  },
207
+ sapiens_distribution: {
208
+ description: "Despachar peças (Distribution Workflow) — a peça pronta entra na FILA com canal, copy e a aba de quem ela é. ADMIN-ONLY: despacho depende de rede conectada e hoje só a casa tem. NADA aqui posta em rede nenhuma; quem despacha é a tela em /experimentos/distribution-workflow, que é onde a conta conectada mora. A ABA (`voice`) responde de quem é a peça: sapiens (a casa), helen-ailith, borderless, ou o slug de um personagem seu — slug livre, então personagem novo ganha aba sozinho na primeira peça dele, sem deploy. Em queue, aba ausente = o servidor deriva do personagem da peça e cai em sapiens quando não há. Sub-actions: queue (põe na fila: title e channel obrigatórios, mais copy/hashtags/assetUrl/notes), list (o que está na fila, filtrável por status e por aba), voices (as abas que existem hoje com a contagem de cada uma), status (move a peça de lane: fila, agendado, postado, descartado; postado aceita postUrl e fecha o rastro, agendado aceita scheduledFor em ms). Sem custo em Sinapses: isto organiza, não gera. A copy segue a voz de QUEM ASSINA a peça, que não é sempre a voz da casa: peça da Helen fala como a Helen.",
209
+ schema: distributionSchema,
210
+ handler: distribution,
211
+ },
206
212
  sapiens_semana: {
207
213
  description: "As Atividades da SUA semana na casa: o que você produziu e quanto XP isso rendeu. Identidade SEMPRE pelo sessionToken. Sub-actions: 'get' (quais atividades você fez nesta semana, quantas peças em cada, o XP já pago, quanto a Casa Cheia renderia no fecho, quanto vale abrir mais uma atividade e QUAIS abrir agora, a sequência de semanas seguidas com o recorde, as semanas anteriores com o que cada uma rendeu, e uma leitura pronta da semana pra você dizer em voz alta), 'fechar' (fecha as semanas pendentes e credita a Casa Cheia de cada uma). Como a régua funciona: cada peça pronta anda o contador da atividade e paga em degraus (1a, 3a, 7a, 15a, 30a peça da semana, com retorno decrescente); no fecho, a LARGURA paga à parte, 2 atividades valem 20 XP, 5 valem 200, 8 valem 560, então atividades diferentes rendem mais que repetir a mesma. Esta tool PAGA XP, não cobra Sinapses. Idempotente: chamar 'fechar' duas vezes não credita duas vezes.",
208
214
  schema: semanaSchema,
@@ -294,6 +300,7 @@ const TOOL_TITLES = {
294
300
  sapiens_atlas: "Atlas Ecossistema IA",
295
301
  sapiens_reference: "Referências",
296
302
  sapiens_trilhas: "Trilhas & Desafios",
303
+ sapiens_distribution: "Despachar peças",
297
304
  sapiens_semana: "Minha Semana",
298
305
  sapiens_instagram: "Auto-DM Instagram",
299
306
  sapiens_share: "Share Drop",
@@ -314,6 +321,9 @@ const ADMIN_ONLY_TOOLS = new Set([
314
321
  "sapiens_share",
315
322
  "sapiens_decupagem",
316
323
  "sapiens_publicidade",
324
+ // Despacho depende de rede conectada, e hoje so a casa tem: a rota tambem e
325
+ // adminOnly. Quando abrir pra membro, sai daqui e do gate da rota juntos.
326
+ "sapiens_distribution",
317
327
  ]);
318
328
  /**
319
329
  * Monta o payload do tools/list pro tier dado. Tier "user" esconde as
@@ -46,7 +46,8 @@ import { convexQuery, convexMutation, convexAction, getSessionToken } from "../c
46
46
  * gente pede o arg no create; quem já existe sem ele conserta com set_card.
47
47
  *
48
48
  * O TRAÇO (`style`) é em que TÉCNICA ele é feito: auto (default), realista,
49
- * editorial (o cartum adulto da casa), anime, manhwa, 3d, custom. É o
49
+ * editorial (o cartum adulto da casa), anime, manhwa, concept (mídia
50
+ * tradicional suja, o traço de criatura), 3d, custom. É o
50
51
  * vocabulário da CASA (convex/shared/visualStyle.ts), o mesmo que o Reflexo de
51
52
  * Si lê. As três peças do personagem leem daqui pra saber se estão
52
53
  * fazendo foto, desenho ou render. No automático a peça não afirma técnica
@@ -132,12 +133,23 @@ export const characterSchema = z.object({
132
133
  "pra decidir se descrevem rosto e mãos ou silhueta e postura, e sem isso o " +
133
134
  "modelo desenha uma pessoa em cima da criatura. Ausente no create = human."),
134
135
  style: z
135
- .enum(["auto", "realista", "editorial", "anime", "manhwa", "3d", "custom"])
136
+ .enum([
137
+ "auto",
138
+ "realista",
139
+ "editorial",
140
+ "anime",
141
+ "manhwa",
142
+ "concept",
143
+ "3d",
144
+ "custom",
145
+ ])
136
146
  .optional()
137
147
  .describe("Pra create/set_card: em que TÉCNICA o personagem é feito. 'auto' (default) " +
138
148
  "não afirma técnica nenhuma e deixa as imagens de referência mandarem; " +
139
149
  "'realista' é fotografia (óptica, luz e pele reais); 'anime' é cel shading " +
140
- "com contorno de tinta; 'manhwa' é pintura digital suave de webtoon; '3d' é " +
150
+ "com contorno de tinta; 'manhwa' é pintura digital suave de webtoon; " +
151
+ "'concept' é mídia tradicional suja, grafite e aguada sobre papel, o " +
152
+ "traço de criatura e bestiário; '3d' é " +
141
153
  "render com material e oclusão; 'custom' usa a linha escrita em styleNote. " +
142
154
  "Irmão de `form`, e a divisão é limpa: a forma diz que CORPO é esse, o traço " +
143
155
  "diz como ele é DESENHADO. Mande sempre que o personagem tiver técnica " +
@@ -461,6 +473,17 @@ export async function character(args) {
461
473
  // com edição dele se houver). Sem `shots`, o servidor escreve um roteiro novo
462
474
  // na hora e cobra do mesmo jeito, então o caminho educado é sempre planejar,
463
475
  // mostrar, e só então gerar.
476
+ //
477
+ // A peça volta FECHADA, sem você pedir nada: o personagem se apresenta (o
478
+ // cartão com o nome dele e o lema em inglês da ficha, por cima do fim do
479
+ // último plano) e depois a casa assina. O fecho é asset, não geração: custa
480
+ // ZERO Sinapse a mais e sai igual toda vez, que é o ponto de uma assinatura.
481
+ //
482
+ // A resposta traz `closed` e `nameCard`. Fecho é fail-open: quando um dos
483
+ // dois volta false, o take é seu do mesmo jeito (nada a mais foi cobrado),
484
+ // só desceu cru. Diga isso ao autor em vez de prometer um cartão que não
485
+ // está no arquivo. Sem lema em inglês na ficha o cartão sai só com o nome:
486
+ // o conserto é sapiens_character action=set_card titleEn=..., de graça.
464
487
  if (args.action === "generate_video") {
465
488
  if (!args.characterId)
466
489
  throw new Error("action=generate_video exige characterId.");
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+ import { convexQuery, convexMutation, getSessionToken } from "../convexClient.js";
3
+ /**
4
+ * sapiens_distribution: o Despachar peças pelo agente.
5
+ *
6
+ * A peça pronta (imagem, vídeo, carrossel, artigo) entra na FILA do Distribution
7
+ * Workflow com canal, copy e a aba de quem ela é. Nada aqui posta em rede
8
+ * nenhuma: quem despacha continua sendo a tela, porque é lá que mora a conta
9
+ * conectada. O que a tool faz é tirar o trabalho de digitar peça por peça.
10
+ *
11
+ * ADMIN-ONLY de propósito. A rota /experimentos/distribution-workflow também é:
12
+ * despacho depende de rede conectada e hoje só a casa tem. Membro que chamar
13
+ * recebe o recado do servidor, não uma tela vazia.
14
+ *
15
+ * A ABA (`voice`) é de quem é a peça: `sapiens` (a casa), `helen-ailith`,
16
+ * `borderless`, ou o slug de um personagem novo. Slug livre: personagem novo
17
+ * ganha aba sozinho quando a primeira peça dele é despachada. Ausente, o
18
+ * servidor deriva do personagem da peça e cai em `sapiens` quando não há.
19
+ *
20
+ * Sub-actions:
21
+ * - queue: põe uma peça na fila (title + channel obrigatórios).
22
+ * - list: o que está na fila, filtrável por status e por aba.
23
+ * - voices: as abas que existem hoje, com a contagem de cada uma.
24
+ * - status: move a peça de lane (fila, agendado, postado, descartado).
25
+ *
26
+ * Sem custo em Sinapses: isto organiza, não gera.
27
+ */
28
+ const CHANNELS = [
29
+ "instagram",
30
+ "youtube",
31
+ "x",
32
+ "tiktok",
33
+ "threads",
34
+ "linkedin",
35
+ "google-business",
36
+ "bluesky",
37
+ "farcaster",
38
+ "telegram",
39
+ "reddit",
40
+ "medium",
41
+ "pinterest",
42
+ ];
43
+ export const distributionSchema = z.object({
44
+ action: z.enum(["queue", "list", "voices", "status"]),
45
+ title: z
46
+ .string()
47
+ .optional()
48
+ .describe("queue: título INTERNO da peça (como você a acha na lista). Obrigatório."),
49
+ channel: z
50
+ .enum(CHANNELS)
51
+ .optional()
52
+ .describe("queue: o canal de destino. Obrigatório."),
53
+ copy: z
54
+ .string()
55
+ .optional()
56
+ .describe("queue: a legenda pronta pra colar, na voz de quem assina a peça. Sem em-dash."),
57
+ hashtags: z.array(z.string()).optional().describe("queue: sem o #, o servidor limpa."),
58
+ assetUrl: z
59
+ .string()
60
+ .optional()
61
+ .describe("queue: a mídia da peça (URL de host Sapiens, a que sapiens_image/sapiens_gallery devolvem)."),
62
+ assetKind: z.enum(["image", "video", "audio"]).optional(),
63
+ voice: z
64
+ .string()
65
+ .optional()
66
+ .describe("A aba de quem é a peça: sapiens, helen-ailith, borderless, ou o slug de um personagem seu. Em queue, ausente = o servidor deriva. Em list, filtra."),
67
+ notes: z.string().optional().describe("queue: recado pra você mesmo na hora de postar."),
68
+ itemId: z.string().optional().describe("status: o id da peça (vem do list ou do queue)."),
69
+ status: z
70
+ .enum(["fila", "agendado", "postado", "descartado"])
71
+ .optional()
72
+ .describe("list: filtra a lane. status: a lane pra onde a peça vai."),
73
+ postUrl: z
74
+ .string()
75
+ .optional()
76
+ .describe("status=postado: o link do post que foi ao ar, pro rastro fechar."),
77
+ scheduledFor: z
78
+ .number()
79
+ .optional()
80
+ .describe("status=agendado: timestamp em ms de quando ela sai."),
81
+ limit: z.number().int().positive().max(60).optional().describe("list: default 20."),
82
+ });
83
+ export async function distribution(args) {
84
+ const sessionToken = getSessionToken();
85
+ if (args.action === "queue") {
86
+ if (!args.title)
87
+ throw new Error("action=queue exige title.");
88
+ if (!args.channel)
89
+ throw new Error("action=queue exige channel.");
90
+ const r = await convexMutation("distributionMcp:mcpQueueItem", {
91
+ sessionToken,
92
+ title: args.title,
93
+ channel: args.channel,
94
+ copy: args.copy,
95
+ hashtags: args.hashtags,
96
+ assetUrl: args.assetUrl,
97
+ assetKind: args.assetKind,
98
+ voice: args.voice,
99
+ notes: args.notes,
100
+ });
101
+ return {
102
+ itemId: r.itemId,
103
+ status: "fila",
104
+ voice: args.voice ?? "(derivado no servidor)",
105
+ instruction: "A peça está na fila do Distribution Workflow, não foi ao ar. Quem posta é a tela, em /experimentos/distribution-workflow.",
106
+ };
107
+ }
108
+ if (args.action === "list") {
109
+ return await convexQuery("distributionMcp:mcpListItems", {
110
+ sessionToken,
111
+ status: args.status,
112
+ voice: args.voice,
113
+ limit: args.limit,
114
+ });
115
+ }
116
+ if (args.action === "voices") {
117
+ return await convexQuery("distributionMcp:mcpVoices", { sessionToken });
118
+ }
119
+ if (args.action === "status") {
120
+ if (!args.itemId)
121
+ throw new Error("action=status exige itemId.");
122
+ if (!args.status)
123
+ throw new Error("action=status exige status.");
124
+ await convexMutation("distributionMcp:mcpSetStatus", {
125
+ sessionToken,
126
+ itemId: args.itemId,
127
+ status: args.status,
128
+ postUrl: args.postUrl,
129
+ scheduledFor: args.scheduledFor,
130
+ });
131
+ return { ok: true, itemId: args.itemId, status: args.status };
132
+ }
133
+ throw new Error(`action desconhecida: ${args.action}`);
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sapiens-mcp",
3
- "version": "1.59.0",
3
+ "version": "1.61.0",
4
4
  "mcpName": "com.sapiensinteticos/sapiens",
5
5
  "description": "MCP server pra operar o Sapiens Sintéticos (sapiensinteticos.com) pelo Claude Code: gerar imagem, escrever artigo, voz, música e mais, na sua conta. Login pelo código de sapiensinteticos.com/conectar-claude.",
6
6
  "type": "module",