sapiens-mcp 1.68.0 → 1.69.1

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
@@ -206,7 +206,7 @@ export const TOOLS = {
206
206
  handler: trilhas,
207
207
  },
208
208
  sapiens_distribution: {
209
- 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). Em queue, DOIS campos que parecem opcionais e não são: `lang` diz em que língua a copy já está, e sem ele canal de rede internacional reescreve a sua copy sozinho, dois segundos depois, na voz da casa; `assetPageAssetId` é o imageId da obra da casa, e sem ele a peça só encontra a obra se a assetUrl bater letra a letra, então versão web de um master nasce órfã de ficha, 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. E a peça sai pela CONTA de quem assina ela: conta extra da mesma rede é um canal próprio (bluesky-2 é outra conta no Bluesky, instagram-pro outra no Instagram), então case o canal com a aba antes de despachar.",
209
+ 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). Em queue, DOIS campos que parecem opcionais e não são: `lang` diz em que língua a copy já está, e sem ele canal de rede internacional reescreve a sua copy sozinho, dois segundos depois, na voz da casa; `assetPageAssetId` é o imageId da obra da casa, e sem ele a peça só encontra a obra se a assetUrl bater letra a letra, então versão web de um master nasce órfã de ficha, 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), bio (lê ou troca a BIO de uma conta da casa no Bluesky, channel bluesky ou bluesky-2 a bluesky-5: sem texto só lê; bioLine acrescenta uma linha no fim sem mexer no resto e não repete linha que já está lá; bio reescreve a inteira; teto de 256; ESTA sub-action muda o perfil público na hora, e bio não aceita hiperlink, o endereço aparece escrito). 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. E a peça sai pela CONTA de quem assina ela: conta extra da mesma rede é um canal próprio (bluesky-2 é outra conta no Bluesky, instagram-pro outra no Instagram), então case o canal com a aba antes de despachar.",
210
210
  schema: distributionSchema,
211
211
  handler: distribution,
212
212
  },
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { convexQuery, convexMutation, getSessionToken } from "../convexClient.js";
2
+ import { convexQuery, convexMutation, convexAction, getSessionToken } from "../convexClient.js";
3
3
  /**
4
4
  * sapiens_distribution: o Despachar peças pelo agente.
5
5
  *
@@ -51,6 +51,12 @@ const CHANNELS = [
51
51
  "bluesky-5",
52
52
  "farcaster",
53
53
  "telegram",
54
+ // Canais de personagem no Telegram (telegram-2 = Aria, telegram-3 = Arak,
55
+ // telegram-4 = Helen, telegram-5 = Borderless), mesmo bot da casa.
56
+ "telegram-2",
57
+ "telegram-3",
58
+ "telegram-4",
59
+ "telegram-5",
54
60
  // nostr: protocolo, nao empresa. Publica por WebSocket atras de "use node".
55
61
  "nostr",
56
62
  // Are.na: um canal por CANAL de la (o Are.na nao tem feed).
@@ -99,7 +105,7 @@ const CHANNELS = [
99
105
  "youtube-5",
100
106
  ];
101
107
  export const distributionSchema = z.object({
102
- action: z.enum(["queue", "list", "voices", "status"]),
108
+ action: z.enum(["queue", "list", "voices", "status", "bio"]),
103
109
  title: z
104
110
  .string()
105
111
  .optional()
@@ -107,7 +113,7 @@ export const distributionSchema = z.object({
107
113
  channel: z
108
114
  .enum(CHANNELS)
109
115
  .optional()
110
- .describe("queue: o canal de destino. Obrigatório. Conta extra da mesma rede é um canal próprio: bluesky-2 a bluesky-5 são OUTRAS contas no Bluesky, instagram-pro e instagram-3..5 outras no Instagram, e assim por diante. A peça sai pela conta de quem assina ela, então case o canal com a aba (`voice`) antes de despachar: peça de personagem no canal de outro só aparece como erro depois de publicada, no perfil errado. Case também o canal com a MÍDIA (ver assetKind): canal de vídeo não recebe foto, canal de imagem não recebe vídeo, e o servidor recusa na fila."),
116
+ .describe("queue: o canal de destino. Obrigatório. Conta extra da mesma rede é um canal próprio: bluesky-2 a bluesky-5 são OUTRAS contas no Bluesky, telegram-2 é o canal da Aria, telegram-3 o da Arak, telegram-4 o da Helen e telegram-5 o do Borderless no Telegram (o telegram é o da casa), instagram-pro e instagram-3..5 outras no Instagram, e assim por diante. A peça sai pela conta de quem assina ela, então case o canal com a aba (`voice`) antes de despachar: peça de personagem no canal de outro só aparece como erro depois de publicada, no perfil errado. Case também o canal com a MÍDIA (ver assetKind): canal de vídeo não recebe foto, canal de imagem não recebe vídeo, e o servidor recusa na fila."),
111
117
  copy: z
112
118
  .string()
113
119
  .optional()
@@ -116,7 +122,15 @@ export const distributionSchema = z.object({
116
122
  assetUrl: z
117
123
  .string()
118
124
  .optional()
119
- .describe("queue: a mídia da peça (URL de host Sapiens, a que sapiens_image/sapiens_gallery devolvem)."),
125
+ .describe("queue: a mídia da peça, UMA só (URL de host Sapiens, a que sapiens_image/sapiens_gallery devolvem). Pra post de várias imagens (carrossel, as 4 do X, álbum), use assets."),
126
+ assets: z
127
+ .array(z.object({
128
+ url: z.string(),
129
+ kind: z.enum(["image", "video", "audio"]).optional(),
130
+ }))
131
+ .max(20)
132
+ .optional()
133
+ .describe("queue: a mídia em LISTA, na ordem do post. Quando vem, ela manda: a 1ª vira a capa e assetUrl/assetKind são ignorados. Cada canal leva só o teto dele e o resto fica de fora na hora do despacho: instagram 10 (carrossel, imagem e vídeo juntos), threads 20, linkedin 20, telegram e telegram-2..5 10 (álbum), x-buffer 4, bluesky e bluesky-2..5 4, linkedin-page 4, farcaster 2, os demais 1. O canal x (API própria do X) NÃO sobe imagem nenhuma, só o texto: post do X com imagem vai por x-buffer. Canal que não mistura (x-buffer, bluesky, linkedin) segue o tipo da 1ª mídia. Não precisa mandar o imageId de cada obra: o servidor casa cada URL com a obra da casa, e toda imagem da casa na lista conta como compartilhada na ficha dela. O Distribution não faz quote de post do X: link de post na copy vai como link."),
120
134
  assetKind: z
121
135
  .enum(["image", "video", "audio"])
122
136
  .optional()
@@ -164,6 +178,14 @@ export const distributionSchema = z.object({
164
178
  .optional()
165
179
  .describe("status=agendado: timestamp em ms de quando ela sai."),
166
180
  limit: z.number().int().positive().max(60).optional().describe("list: default 20."),
181
+ bio: z
182
+ .string()
183
+ .optional()
184
+ .describe("bio: a bio INTEIRA nova da conta do Bluesky em `channel` (bluesky, bluesky-2 a bluesky-5). Reescreve tudo. Teto de 256 caracteres. Use bioLine quando só quer acrescentar."),
185
+ bioLine: z
186
+ .string()
187
+ .optional()
188
+ .describe("bio: UMA linha acrescentada no fim da bio atual, sem mexer no resto (ex: o CTA com t.me/<handle> do Telegram da personagem). Linha que já está na bio não entra de novo. Bio NÃO aceita hiperlink: o endereço aparece escrito e o app pinta de azul."),
167
189
  });
168
190
  export async function distribution(args) {
169
191
  const sessionToken = getSessionToken();
@@ -180,6 +202,7 @@ export async function distribution(args) {
180
202
  hashtags: args.hashtags,
181
203
  assetUrl: args.assetUrl,
182
204
  assetKind: args.assetKind,
205
+ assets: args.assets,
183
206
  assetPageAssetId: args.assetPageAssetId,
184
207
  assetPagePath: args.assetPagePath,
185
208
  lang: args.lang,
@@ -221,5 +244,27 @@ export async function distribution(args) {
221
244
  });
222
245
  return { ok: true, itemId: args.itemId, status: args.status };
223
246
  }
247
+ if (args.action === "bio") {
248
+ if (!args.channel)
249
+ throw new Error("action=bio exige channel (bluesky, bluesky-2 a bluesky-5).");
250
+ if (args.bio !== undefined && args.bioLine !== undefined) {
251
+ throw new Error("action=bio: mande bio (a inteira) OU bioLine (uma linha no fim), não os dois.");
252
+ }
253
+ const r = await convexAction("blueskyProfile:mcpHouseBio", {
254
+ sessionToken,
255
+ channel: args.channel,
256
+ bio: args.bio,
257
+ bioLine: args.bioLine,
258
+ });
259
+ const lendo = args.bio === undefined && args.bioLine === undefined;
260
+ return {
261
+ ...r,
262
+ instruction: lendo
263
+ ? "Esta é a bio atual da conta. Pra acrescentar uma linha sem reescrever, chame de novo com bioLine."
264
+ : r.mudou
265
+ ? "A bio foi trocada e já está no ar no Bluesky. Mostre ao dono o antes e o depois."
266
+ : "Nada mudou: a linha já estava na bio (ou o texto é igual ao atual).",
267
+ };
268
+ }
224
269
  throw new Error(`action desconhecida: ${args.action}`);
225
270
  }
@@ -81,7 +81,7 @@ export const imageSchema = z.object({
81
81
  model: z
82
82
  .enum(MODELS)
83
83
  .optional()
84
- .describe("Default 'nano-banana-2' (Flash 3.1 com refs). 'nano-banana-max' (Pro 3) = qualidade alta. 'gpt-image-2-low/high' = GPT Image 2 nos tiers low e high. 'gpt-image-2-5-flare'/'gpt-image-2-5-sunburst' = GPT Image 2.5, a geração de set/2026, os dois em quality high e com referência: o Flare é o rápido, pra volume; o Sunburst é o de precisão, pra composição complexa e edição em várias voltas. 'mai-image-2-6' (MAI Image 2.6, da Microsoft) = foto rápida no mesmo recurso do gpt-image-2, e o único da casa que cobra por ÁREA: o adder de resolução aqui é real, o teto é 2K (1536², porque acima disso o provider recusa por total de pixels) e ele não aceita referência. 'muse-image' (Muse Image, da Meta) = barato na edição por referência e bom pra segurar personagem (10 refs no catálogo; pelo MCP vale o teto de 5 do campo referenceImageUrls); sem escada de resolução (o motor decide o tamanho e cobra o mesmo) e moderação apertada, NÃO serve pra +18. 'seedream-4-5'/'seedream-5-0'/'seedream-5-0-pro' = ByteDance 2K nativo, cinematográfico, aceita até 4 referências (o 5.0 é a geração nova, entende prompt complexo melhor; o 5.0-pro é o topo da linha). 'grok-2-image'/'grok-2-image-quality' = xAI Grok Imagine da geração anterior (moderação frouxa +18, aceita refs e aspect; quality é mais fiel pra character lock); 'grok-imagine-2' = Grok Imagine Image 2.0, a geração nova de ago/2026, que é a melhor da linha integrando desenho e foto na mesma peça. DEGEN (uncensored, gate +18): 'wavespeed-chroma' (fotorrealista rápido), 'wavespeed-flux2' (Flux.2 Klein), 'wavespeed-klein-plus' (o MESMO Klein 9B com uma LoRA de ANATOMIA por cima, e é o caminho de nudez explícita com personagem travada: o Klein base desenha aréola e mamilo mas devolve a virilha lisa, e os motores que desenham a anatomia ignoram a referência. Aqui a identidade continua vindo da ref e a LoRA só preenche o que faltava; Ousadia regulável), 'wavespeed-flux-nsfw' (flux+LoRA NSFW, Ousadia regulável via loraIntensity), 'wavespeed-klein-anime' (Flux.2 Klein + LoRA anime, inteligente+controlável), 'wavespeed-klein-anime-plus' (Klein anime +18, Ousadia regulável), 'wavespeed-klein-celular' (o MESMO Klein 9B com a LoRA Phone Photography por cima: foto de celular, candid, luz de janela; no edit com a referência da personagem o rosto fica quase idêntico, e é a receita de conteúdo de perfil de criadora pra personagem FOTOGRÁFICA. Em personagem cel-shaded o edit troca o traço, então não use com a Aria. Comece o prompt com 'This is a candid photograph taken with a smartphone of' e enumere 'same face, same hair' antes da cena; sem Ousadia), 'wavespeed-krea2' (Krea 2 Livre: a MESMA base 12B das fal-krea2-*, hospedada na WaveSpeed, SEM o classificador de entrada da fal: é o caminho quando a fal devolve 422 num prompt que não tem palavra de nudez; aceita referência img2img de verdade, Ousadia regulável e 2K), 'wavespeed-krea2-base' (Krea 2 Base: a mesma base 12B da Livre SEM LoRA nenhuma, nem realismo nem NSFW; é o motor como ele é, com img2img e 2K, pra quem quer ver a base crua ou temperar com o próprio prompt; sem Ousadia, que é a LoRA que ele não carrega) = WaveSpeed rápido; 'civitai-wai-illustrious'/'civitai-nova-anime-xl' (anime), 'civitai-pony-v6' (Pony V6 XL, base nº1) = Civitai sdcpp rápido. 'civitai-anima' (Anima: 2B da CircleStone com a Comfy Org, base própria e não SDXL; entrega anime de PRODUÇÃO, linha fechada e sombra chapada, em vez do registro de ilustração dos Illustrious. O encoder é um LLM, então escreva a cena em FRASE e não em tag booru, e não cole score_9/masterpiece aqui). 'fal-krea2-realism-v2' (na tela chama Krea 2 Realism: Krea-2 Turbo 12B + LoRA de realismo, fal.ai, ~4s, pele crua e contraluz que não lava; o sufixo -v2 do id é o nome do arquivo de LoRA, não geração nova do motor) = aceita até 3 referências de ESTILO (paleta/luz/textura de uma série), não character lock; com referência a LoRA não vai junto."),
84
+ .describe("Default 'nano-banana-2' (Flash 3.1 com refs). 'nano-banana-max' (Pro 3) = qualidade alta. 'gpt-image-2-low/high' = GPT Image 2 nos tiers low e high. 'gpt-image-2-5-flare'/'gpt-image-2-5-sunburst' = GPT Image 2.5, a geração de set/2026, os dois em quality high e com referência: o Flare é o rápido, pra volume; o Sunburst é o de precisão, pra composição complexa e edição em várias voltas. 'mai-image-2-6' (MAI Image 2.6, da Microsoft) = foto rápida no mesmo recurso do gpt-image-2, e o único da casa que cobra por ÁREA: o adder de resolução aqui é real, o teto é 2K (1536², porque acima disso o provider recusa por total de pixels) e ele não aceita referência. 'muse-image' (Muse Image, da Meta) = barato na edição por referência e bom pra segurar personagem (10 refs no catálogo; pelo MCP vale o teto de 5 do campo referenceImageUrls); sem escada de resolução (o motor decide o tamanho e cobra o mesmo) e moderação apertada, NÃO serve pra +18. 'seedream-4-5'/'seedream-5-0'/'seedream-5-0-pro' = ByteDance 2K nativo, cinematográfico, aceita até 4 referências (o 5.0 é a geração nova, entende prompt complexo melhor; o 5.0-pro é o topo da linha). 'grok-2-image'/'grok-2-image-quality' = xAI Grok Imagine da geração anterior (moderação frouxa +18, aceita refs e aspect; quality é mais fiel pra character lock); 'grok-imagine-2' = Grok Imagine Image 2.0, a geração nova de ago/2026, que é a melhor da linha integrando desenho e foto na mesma peça. DEGEN (uncensored, gate +18). NUDEZ É NÍVEL, NÃO MOTOR: três escolhas têm um par com nudez, e o par vem no campo `ousadia` de action=models. Sem nudez = o id da escolha; com nudez = o id do par + loraIntensity. Não existe motor '+18', 'Nu' ou 'Livre' separado pra procurar. 'wavespeed-chroma' (fotorrealista rápido, sem referência), 'wavespeed-flux2' (Flux.2 Klein Base: foto rápida, até 4 referências, segura o rosto) · com nudez = 'wavespeed-klein-nu' (o mesmo Klein com a LoRA de nudez no registro de foto; a identidade continua vindo da referência), 'wavespeed-klein-anime' (Flux.2 Klein + LoRA anime, inteligente e controlável) · com nudez = 'wavespeed-klein-anime-plus', 'wavespeed-flux-nsfw' (Flux dev + LoRA NSFW, sem par: a Ousadia é dele mesmo, via loraIntensity), 'wavespeed-klein-celular' (o MESMO Klein 9B com a LoRA Phone Photography por cima: foto de celular, candid, luz de janela; no edit com a referência da personagem o rosto fica quase idêntico, e é a receita de conteúdo de perfil de criadora pra personagem FOTOGRÁFICA. Em personagem cel-shaded o edit troca o traço, então não use com a Aria. Comece o prompt com 'This is a candid photograph taken with a smartphone of' e enumere 'same face, same hair' antes da cena; sem Ousadia), 'wavespeed-klein-transparencia' (o MESMO Klein 9B com a LoRA de tecido transparente: o efeito vem da LoRA e não da descrição; segura o rosto da ref; sem Ousadia), 'wavespeed-krea2-realism' (Krea 2 Realism: base 12B com LoRA de realismo, pele crua, hospedada na WaveSpeed SEM o classificador de entrada da fal, que devolve 422 até em prompt sem palavra de nudez; img2img de verdade com 1 referência e 2K) · com nudez = 'wavespeed-krea2' (o mesmo realismo + LoRA NSFW; é a antiga 'Krea 2 Livre'), 'wavespeed-krea2-transparencia' (a mesma LoRA de transparência na base Krea 2: fotografia mais rica, identidade mais frouxa que a irmã Klein; 1 referência; sem Ousadia) = WaveSpeed rápido. LEGADO, fora da escolha da tela e ainda gerando pelo id (não ofereça): 'wavespeed-klein-plus' (a escolha virou 'wavespeed-klein-nu'), 'wavespeed-krea2-base' (Krea 2 sem LoRA nenhuma; a escolha virou 'wavespeed-krea2-realism'), 'fal-krea2-realism-v2' (Krea 2 Realism pela fal, ~4s: aceita até 3 referências de ESTILO, paleta/luz/textura de uma série, não character lock, e com referência a LoRA não vai junto; a escolha virou 'wavespeed-krea2-realism'). 'civitai-wai-illustrious'/'civitai-nova-anime-xl' (anime), 'civitai-pony-v6' (Pony V6 XL, base nº1) = Civitai sdcpp rápido. 'civitai-anima' (Anima: 2B da CircleStone com a Comfy Org, base própria e não SDXL; entrega anime de PRODUÇÃO, linha fechada e sombra chapada, em vez do registro de ilustração dos Illustrious. O encoder é um LLM, então escreva a cena em FRASE e não em tag booru, e não cole score_9/masterpiece aqui)."),
85
85
  aspectRatio: z
86
86
  .enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"])
87
87
  .optional()
@@ -98,7 +98,7 @@ export const imageSchema = z.object({
98
98
  referenceImageUrls: z
99
99
  .array(httpUrl())
100
100
  .optional()
101
- .describe("URLs públicas de referência pra combinar numa geração só (character/style lock), igual ao modal 'Selecionar Referência' do gerador web. Fontes: sua galeria (sapiens_gallery, campo url), o Acervo, e personagens públicos (sapiens_character action=list_public → mainImageUrl/imageUrls). Restrito a hosts do Sapiens (Bunny CDN / Convex) + Wikimedia. Requer model com refs (o campo supportsReferences em action=models é a fonte): nano-banana-*, gpt-image-2-*, muse-image, seedream-*, grok-* (até 3), wavespeed-krea2 e wavespeed-krea2-base (img2img: a primeira referência vira a imagem-base, 1 ref) ou fal-krea2-* (referência de ESTILO, teto de 3). Soma com sourceImageIds: até 5 no total (acima disso o servidor recusa a chamada), e cada motor corta no seu teto quando ele é menor (Seedream 4, Grok 3, Krea 2 Livre/Base 1; o campo maxReferences em action=models é a fonte)."),
101
+ .describe("URLs públicas de referência pra combinar numa geração só (character/style lock), igual ao modal 'Selecionar Referência' do gerador web. Fontes: sua galeria (sapiens_gallery, campo url), o Acervo, e personagens públicos (sapiens_character action=list_public → mainImageUrl/imageUrls). Restrito a hosts do Sapiens (Bunny CDN / Convex) + Wikimedia. Requer model com refs (o campo supportsReferences em action=models é a fonte): nano-banana-*, gpt-image-2-*, muse-image, seedream-*, grok-* (até 3), a família Klein (wavespeed-flux2 e wavespeed-klein-*, até 4), wavespeed-flux-nsfw (1), a família Krea 2 da WaveSpeed (wavespeed-krea2-realism, wavespeed-krea2 e wavespeed-krea2-transparencia; img2img: a primeira referência vira a imagem-base, 1 ref) ou fal-krea2-* (referência de ESTILO, teto de 3). Soma com sourceImageIds: até 5 no total (acima disso o servidor recusa a chamada), e cada motor corta no seu teto quando ele é menor (Seedream 4, Klein 4, Grok 3, Krea 2 e Flux NSFW 1; o campo maxReferences em action=models é a fonte)."),
102
102
  sourceImageIds: z
103
103
  .array(z.string())
104
104
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sapiens-mcp",
3
- "version": "1.68.0",
3
+ "version": "1.69.1",
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",