sapiens-mcp 1.72.0 → 1.74.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
@@ -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), 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.",
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), lineages (o CADASTRO das linhagens, o mesmo da aba Teia: de cada personagem, produto e da casa, a mãe no Bluesky onde a peça nasce, as contas próprias, as galerias que a mãe alimenta sozinha, as fichas e o post do dia, mais as regras que a teia desdobra e as vagas de conta ainda sem dona), lineage-new (nasce uma linhagem: nome obrigatório, grupo, artigo, lang; nasce sem mãe, então nada viaja sozinho até o lineage-save dar a mãe), lineage-save (slug e só o que muda: mae, contas rede->canal, galerias, fichaIds, rotina, contaNaCasa; o servidor recusa conta que já é de outra linhagem e canal de outra rede, e a vaga assumida ganha o nome da linhagem), lineage-archive (slug + arquivada). 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
  },
@@ -22,6 +22,11 @@ import { convexQuery, convexMutation, convexAction, getSessionToken } from "../c
22
22
  * - list: o que está na fila, filtrável por status e por aba.
23
23
  * - voices: as abas que existem hoje, com a contagem de cada uma.
24
24
  * - status: move a peça de lane (fila, agendado, postado, descartado).
25
+ * - lineages / lineage-new / lineage-save / lineage-archive: o CADASTRO das
26
+ * linhagens (personagens, produtos, a casa), o mesmo que a aba Teia edita:
27
+ * a mãe no Bluesky, as contas próprias, as galerias que a mãe alimenta, as
28
+ * fichas e o post do dia. É ele que decide por qual conta cada peça sai e
29
+ * o que viaja sozinho depois.
25
30
  *
26
31
  * Sem custo em Sinapses: isto organiza, não gera.
27
32
  */
@@ -49,6 +54,10 @@ const CHANNELS = [
49
54
  "bluesky-3",
50
55
  "bluesky-4",
51
56
  "bluesky-5",
57
+ "bluesky-6",
58
+ "bluesky-7",
59
+ "bluesky-8",
60
+ "bluesky-9",
52
61
  "farcaster",
53
62
  "telegram",
54
63
  // Canais de personagem no Telegram (telegram-2 = Aria, telegram-3 = Arak,
@@ -57,6 +66,9 @@ const CHANNELS = [
57
66
  "telegram-3",
58
67
  "telegram-4",
59
68
  "telegram-5",
69
+ "telegram-6",
70
+ "telegram-7",
71
+ "telegram-8",
60
72
  // nostr: protocolo, nao empresa. Publica por WebSocket atras de "use node".
61
73
  "nostr",
62
74
  // Are.na: um canal por CANAL de la (o Are.na nao tem feed).
@@ -92,10 +104,17 @@ const CHANNELS = [
92
104
  // Segunda via pelo Buffer (conta que a casa liga lá).
93
105
  "x-buffer",
94
106
  "tiktok-buffer",
107
+ // X e LinkedIn do Obsolete Human, pelo Buffer próprio do selo.
108
+ "x-buffer-2",
109
+ "x-buffer-3",
110
+ "x-buffer-4",
111
+ "linkedin-page-2",
95
112
  // Vagas numeradas de conta extra.
96
113
  "instagram-3",
97
114
  "instagram-4",
98
115
  "instagram-5",
116
+ "instagram-6",
117
+ "instagram-7",
99
118
  "threads-3",
100
119
  "threads-4",
101
120
  "threads-5",
@@ -105,7 +124,17 @@ const CHANNELS = [
105
124
  "youtube-5",
106
125
  ];
107
126
  export const distributionSchema = z.object({
108
- action: z.enum(["queue", "list", "voices", "status", "bio"]),
127
+ action: z.enum([
128
+ "queue",
129
+ "list",
130
+ "voices",
131
+ "status",
132
+ "bio",
133
+ "lineages",
134
+ "lineage-new",
135
+ "lineage-save",
136
+ "lineage-archive",
137
+ ]),
109
138
  title: z
110
139
  .string()
111
140
  .optional()
@@ -113,7 +142,7 @@ export const distributionSchema = z.object({
113
142
  channel: z
114
143
  .enum(CHANNELS)
115
144
  .optional()
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."),
145
+ .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, x-buffer-2 e linkedin-page-2 o X e o LinkedIn do Obsolete Human (selo de arte, em inglês, voice obsolete-human), 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."),
117
146
  copy: z
118
147
  .string()
119
148
  .optional()
@@ -146,7 +175,7 @@ export const distributionSchema = z.object({
146
175
  lang: z
147
176
  .enum(["pt", "en"])
148
177
  .optional()
149
- .describe("queue: em que LÍNGUA a copy JÁ ESTÁ. Declare sempre que escrever a copy você mesmo. Sem este campo, canal de rede internacional (bluesky, x, linkedin, farcaster, civitai, pinterest, reddit, medium, tumblr, deviantart) presume que a copy chegou em português e agenda uma vertida automática que SOBRESCREVE o que você mandou, dois segundos depois de enfileirar. Copy que já estava em inglês volta reescrita, e na voz da CASA em vez da voz de quem assina a peça, o que estraga copy de personagem. Declarar o idioma desliga a vertida e o texto fica exatamente como você mandou."),
178
+ .describe("lineage-new/lineage-save: a língua em que a linhagem fala. queue: em que LÍNGUA a copy JÁ ESTÁ. Declare sempre que escrever a copy você mesmo. Sem este campo, canal de rede internacional (bluesky, x, linkedin, farcaster, civitai, pinterest, reddit, medium, tumblr, deviantart) presume que a copy chegou em português e agenda uma vertida automática que SOBRESCREVE o que você mandou, dois segundos depois de enfileirar. Copy que já estava em inglês volta reescrita, e na voz da CASA em vez da voz de quem assina a peça, o que estraga copy de personagem. Declarar o idioma desliga a vertida e o texto fica exatamente como você mandou."),
150
179
  voice: z
151
180
  .string()
152
181
  .optional()
@@ -186,6 +215,60 @@ export const distributionSchema = z.object({
186
215
  .string()
187
216
  .optional()
188
217
  .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."),
218
+ slug: z
219
+ .string()
220
+ .optional()
221
+ .describe("lineage-save/lineage-archive: a linhagem (o slug que lineages devolve: sapiens, borderless, helen-inbt, aria, arak, giants...). lineage-new: opcional, sai do nome quando ausente."),
222
+ nome: z.string().optional().describe("lineage-new: o nome da linhagem (obrigatório). lineage-save: renomeia."),
223
+ grupo: z
224
+ .enum(["casa", "personagens", "produtos"])
225
+ .optional()
226
+ .describe("lineage-new/lineage-save: a gaveta. casa é só da casa e do dono. Default produtos."),
227
+ artigo: z.enum(["a", "o"]).optional().describe("lineage-new/lineage-save: o artigo do nome (a Aria, o Arak)."),
228
+ ordem: z.number().optional().describe("lineage-save: a posição na lista."),
229
+ quem: z
230
+ .string()
231
+ .nullable()
232
+ .optional()
233
+ .describe("lineage-save: como a tela diz de quem é (\"da casa\", \"do dono\"). null limpa."),
234
+ mae: z
235
+ .string()
236
+ .nullable()
237
+ .optional()
238
+ .describe("lineage-save: a MÃE da linhagem, a conta do Bluesky onde a peça nasce e de onde a teia desdobra pro resto (bluesky-2..9). Vaga livre sai de lineages (vagasLivres.bluesky). null tira a mãe. A mãe da casa e a do dono não trocam."),
239
+ contas: z
240
+ .record(z.string(), z.string())
241
+ .optional()
242
+ .describe("lineage-save: as contas PRÓPRIAS da linhagem, rede -> canal, ex: {\"telegram\":\"telegram-6\",\"instagram\":\"instagram-6\",\"x\":\"x-buffer-3\"}. Substitui o mapa inteiro. O servidor recusa canal de outra rede e canal que já é de outra linhagem."),
243
+ galerias: z
244
+ .object({
245
+ telegram: z.boolean(),
246
+ arena: z.boolean(),
247
+ tumblr: z.boolean(),
248
+ deviantart: z.boolean(),
249
+ civitai: z.boolean(),
250
+ proprias: z.array(z.string()),
251
+ })
252
+ .optional()
253
+ .describe("lineage-save: o que a mãe alimenta sozinha quando a peça dela vai ao ar. telegram exige conta de telegram em contas; proprias lista as redes de contas (instagram, x...) que também recebem. Manda o objeto inteiro."),
254
+ fichaIds: z
255
+ .array(z.string())
256
+ .optional()
257
+ .describe("lineage-save: as fichas de personagem da linhagem (ids de sapiens_character), a principal primeiro, até 6. É o que trava a peça dela fora das contas dela e o que dá a ficha ao post de texto na conta dela."),
258
+ contaNaCasa: z
259
+ .string()
260
+ .nullable()
261
+ .optional()
262
+ .describe("lineage-save: o username da conta dela aqui na casa (o perfil público). null limpa."),
263
+ rotina: z
264
+ .object({ ligada: z.boolean(), canais: z.array(z.string()) })
265
+ .nullable()
266
+ .optional()
267
+ .describe("lineage-save: o post do dia da linhagem, ligado ou não, e por quais canais sai. null volta ao padrão."),
268
+ arquivada: z
269
+ .boolean()
270
+ .optional()
271
+ .describe("lineage-archive: true arquiva, false devolve. A casa e o dono não se arquivam."),
189
272
  });
190
273
  export async function distribution(args) {
191
274
  const sessionToken = getSessionToken();
@@ -266,5 +349,67 @@ export async function distribution(args) {
266
349
  : "Nada mudou: a linha já estava na bio (ou o texto é igual ao atual).",
267
350
  };
268
351
  }
352
+ if (args.action === "lineages") {
353
+ const r = await convexQuery("distributionMcp:mcpLinhagens", { sessionToken });
354
+ return {
355
+ ...r,
356
+ instruction: "Cada linhagem: mae (a conta do Bluesky onde a peça nasce), contas (as próprias, rede -> canal), galerias (o que a mãe alimenta sozinha), fichaIds, rotina (post do dia). regras é o que a teia desdobra desse cadastro. vagasLivres são as contas que existem no código e ainda não têm dona. semeada=false quer dizer que a tabela ainda roda a fábrica do código; a primeira edição grava.",
357
+ };
358
+ }
359
+ if (args.action === "lineage-new") {
360
+ if (!args.nome)
361
+ throw new Error("action=lineage-new exige nome.");
362
+ const r = await convexMutation("distributionMcp:mcpCriarLinhagem", {
363
+ sessionToken,
364
+ nome: args.nome,
365
+ slug: args.slug,
366
+ grupo: args.grupo,
367
+ artigo: args.artigo,
368
+ lang: args.lang,
369
+ });
370
+ return {
371
+ ...r,
372
+ instruction: r.voltou
373
+ ? "A linhagem estava arquivada e voltou com o cadastro que tinha."
374
+ : "A linhagem nasceu sem mãe e sem regra: nada viaja sozinho a partir dela até lineage-save dar a mãe (vaga livre em lineages).",
375
+ };
376
+ }
377
+ if (args.action === "lineage-save") {
378
+ if (!args.slug)
379
+ throw new Error("action=lineage-save exige slug.");
380
+ await convexMutation("distributionMcp:mcpSalvarLinhagem", {
381
+ sessionToken,
382
+ slug: args.slug,
383
+ nome: args.nome,
384
+ grupo: args.grupo,
385
+ artigo: args.artigo,
386
+ lang: args.lang,
387
+ ordem: args.ordem,
388
+ quem: args.quem,
389
+ mae: args.mae,
390
+ contas: args.contas,
391
+ galerias: args.galerias,
392
+ fichaIds: args.fichaIds,
393
+ contaNaCasa: args.contaNaCasa,
394
+ rotina: args.rotina,
395
+ });
396
+ return {
397
+ ok: true,
398
+ slug: args.slug,
399
+ instruction: "Cadastro salvo. A teia já lê o novo (a próxima peça da mãe desdobra pelas regras novas). Vaga de reserva que a linhagem assumiu ganhou o nome dela; a credencial da conta (env do Convex) continua sendo do dono.",
400
+ };
401
+ }
402
+ if (args.action === "lineage-archive") {
403
+ if (!args.slug)
404
+ throw new Error("action=lineage-archive exige slug.");
405
+ if (args.arquivada === undefined)
406
+ throw new Error("action=lineage-archive exige arquivada (true ou false).");
407
+ await convexMutation("distributionMcp:mcpArquivarLinhagem", {
408
+ sessionToken,
409
+ slug: args.slug,
410
+ arquivada: args.arquivada,
411
+ });
412
+ return { ok: true, slug: args.slug, arquivada: args.arquivada };
413
+ }
269
414
  throw new Error(`action desconhecida: ${args.action}`);
270
415
  }
@@ -84,7 +84,7 @@ export const repertorioSchema = z.object({
84
84
  .number()
85
85
  .nullable()
86
86
  .optional()
87
- .describe("0-10. Pra update_item: passe null pra remover rating."),
87
+ .describe("0-10, nota da OBRA. Pra update_item: passe null pra remover rating. Pessoa (mediaType person) não leva rating: dar nota pra gente soa esquisito, o que ela fez ganha nota na ficha de cada obra. Não mande nem pergunte nota de pessoa."),
88
88
  tags: z.array(z.string()).optional(),
89
89
  note: z.string().optional().describe("Nota pessoal sobre a obra."),
90
90
  containsSpoilers: z.boolean().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sapiens-mcp",
3
- "version": "1.72.0",
3
+ "version": "1.74.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",