sapiens-mcp 1.76.0 → 1.77.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 +7 -1
- package/dist/skills.js +0 -1
- package/dist/tools/distribution.js +33 -12
- package/dist/tools/gallery.js +1 -1
- package/dist/tools/instagram.js +2 -1
- package/dist/tools/meta.js +5 -4
- package/dist/tools/shareDrop.js +1 -1
- package/dist/tools/sintetico.js +1 -1
- package/dist/tools/studios.js +1 -1
- package/package.json +1 -1
package/dist/registry.js
CHANGED
|
@@ -48,6 +48,12 @@ import { skillMenuLine } from "./skills.js";
|
|
|
48
48
|
* pelos DOIS transportes: o stdio (index.ts, pacote npm/npx) e o remoto
|
|
49
49
|
* streamable HTTP (remote.ts, rota /api/mcp do site). Mexeu aqui, mexeu nos
|
|
50
50
|
* dois ao mesmo tempo — é o ponto.
|
|
51
|
+
*
|
|
52
|
+
* Tool nova ou removida aqui: atualize junto o EXPECTED_TOOLS de
|
|
53
|
+
* test/server.test.mjs e as contagens fixas de test/remote.test.mjs e
|
|
54
|
+
* test/remote-protect.test.mjs (admin e user), senão o gate de teste do
|
|
55
|
+
* release.sh fica vermelho e parece culpa da mudança seguinte (origem:
|
|
56
|
+
* 07c9c77c5).
|
|
51
57
|
*/
|
|
52
58
|
export const TOOLS = {
|
|
53
59
|
sapiens_pipeline: {
|
|
@@ -206,7 +212,7 @@ export const TOOLS = {
|
|
|
206
212
|
handler: trilhas,
|
|
207
213
|
},
|
|
208
214
|
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), sign (liga ou desliga a ASSINATURA
|
|
215
|
+
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; num canal do Instagram, format instagram_story faz a peça sair como STORY: uma mídia só, sem legenda nem link, some em 24h). 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), sign (liga ou desliga a ASSINATURA da peça, imagem e vídeo do CDN da casa, com o carimbo da LINHAGEM de quem assina: sint.fyi/<endereço dela> no canto e o fecho de 2s no vídeo, ou a marca própria dela sem nada da casa; itemId, e signed com true de default; o carimbo da casa é recusado em peça +18 e praça adulta, a marca própria passa; o carimbo leva uns 30s e até lá a peça não sai; em queue, signed:true já enfileira assinada), 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, assinatura {estilo casa|propria|nenhuma, marca, padrao}; 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
216
|
schema: distributionSchema,
|
|
211
217
|
handler: distribution,
|
|
212
218
|
},
|
package/dist/skills.js
CHANGED
|
@@ -60,7 +60,6 @@ Não despeje a lista inteira de tools. O start guia.
|
|
|
60
60
|
| imagem | \`sapiens_gallery action=list\` |
|
|
61
61
|
| artigo do perfil | \`sapiens_write action=list\` |
|
|
62
62
|
| carrossel | \`sapiens_pipeline action=list_carousels\` |
|
|
63
|
-
| pipeline | /dashboard/admin/content |
|
|
64
63
|
|
|
65
64
|
**2. Disjuntor anti-loop.** Três falhas seguidas no MESMO tool fazem o cliente marcar o servidor como "unreachable" por ~56s. Parece que "o MCP caiu", mas foi argumento faltando. Quando um tool volta erro de validação ("exige X", "falta Y"), LEIA o erro e refaça a chamada COM o que falta. Nunca repita a chamada idêntica que falhou.
|
|
66
65
|
|
|
@@ -18,13 +18,16 @@ import { convexQuery, convexMutation, convexAction, describeConvexError, getSess
|
|
|
18
18
|
* servidor deriva do personagem da peça e cai em `sapiens` quando não há.
|
|
19
19
|
*
|
|
20
20
|
* Sub-actions:
|
|
21
|
-
* - queue: põe uma peça na fila (title + channel obrigatórios).
|
|
21
|
+
* - queue: põe uma peça na fila (title + channel obrigatórios). Num canal
|
|
22
|
+
* do Instagram, `format: "instagram_story"` faz a peça sair como STORY.
|
|
22
23
|
* - list: o que está na fila, filtrável por status e por aba.
|
|
23
24
|
* - voices: as abas que existem hoje, com a contagem de cada uma.
|
|
24
25
|
* - status: move a peça de lane (fila, agendado, postado, descartado).
|
|
25
|
-
* - sign: liga ou desliga a ASSINATURA
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* - sign: liga ou desliga a ASSINATURA da peça (imagem e vídeo). O carimbo
|
|
27
|
+
* é o da LINHAGEM de quem assina: sint.fyi/<endereço dela> (e o fecho de 2s
|
|
28
|
+
* no vídeo) ou a marca própria dela, sem nada da casa. A mesma chave da
|
|
29
|
+
* ficha, com as mesmas travas no servidor. Em queue, `signed: true` já
|
|
30
|
+
* enfileira assinada; em lineage-save, `assinatura` escolhe o carimbo.
|
|
28
31
|
* - lineages / lineage-new / lineage-save / lineage-archive: o CADASTRO das
|
|
29
32
|
* linhagens (personagens, produtos, a casa), o mesmo que a aba Teia edita:
|
|
30
33
|
* a mãe no Bluesky, as contas próprias, as galerias que a mãe alimenta, as
|
|
@@ -197,10 +200,14 @@ export const distributionSchema = z.object({
|
|
|
197
200
|
.optional()
|
|
198
201
|
.describe("queue, só canais fanvue e fanvue-dm: preço em CENTAVOS de dólar (pay-per-view). 1200 = $12. Piso de 300 na API deles, e peça paga EXIGE mídia. Ausente ou 0 = de graça pra quem já tem acesso."),
|
|
199
202
|
notes: z.string().optional().describe("queue: recado pra você mesmo na hora de postar."),
|
|
203
|
+
format: z
|
|
204
|
+
.enum(["instagram_story"])
|
|
205
|
+
.optional()
|
|
206
|
+
.describe("queue, só canal do Instagram (instagram, instagram-pro, instagram-3..7): instagram_story faz a peça sair como STORY em vez de post no feed. O story leva UMA mídia (a 1a imagem ou vídeo; mande só ela em assets), some em 24h e vai SEM legenda, link nem sticker, porque a API do story não aceita: tudo que o post diz tem que estar na imagem (pro card do Repertório, o card em pé, --formato story no script da skill indica). A imagem sai num quadro 9:16 com a peça inteira no meio. Feed e story da mesma obra na mesma conta convivem; story repetido é recusado. Ausente = feed. Fora do Instagram o campo não muda nada."),
|
|
200
207
|
signed: z
|
|
201
208
|
.boolean()
|
|
202
209
|
.optional()
|
|
203
|
-
.describe("sign: true liga (o default), false desliga. queue: true enfileira a peça já com a assinatura ligada. A ASSINATURA carimba o VÍDEO da peça com sint.fyi/<dono> no canto e o fecho de 2 segundos no fim (o vídeo fica 2s mais longo)
|
|
210
|
+
.describe("sign: true liga (o default), false desliga. queue: true enfileira a peça já com a assinatura ligada. A ASSINATURA carimba a IMAGEM e o VÍDEO da peça que moram no CDN da casa (o que sapiens_image/sapiens_video/sapiens_gallery devolvem), com o carimbo da LINHAGEM de quem assina a peça (a aba dela, ver lineages): no estilo casa, sint.fyi/<conta da linhagem na casa, ou o dono> no canto e, no vídeo, o fecho de 2 segundos no fim (o vídeo fica 2s mais longo); no estilo propria, só a marca da linhagem (ex: Velourie), sem nada da casa e sem fecho; no estilo nenhuma, o servidor recusa. O carimbo da casa é RECUSADO em peça +18 e em praça com teto adulto (fanvue, fanvue-dm, pornhub, civitai-red), porque sint.fyi é endereço da casa; a marca própria passa. A imagem do feed do Instagram é carimbada já recortada pra 4:5 a 1.91:1. O carimbo leva uns 30s na primeira vez (na hora quando a mídia já foi assinada antes), e enquanto ele não fica pronto a peça NÃO sai: o botão de postar da tela devolve o motivo."),
|
|
204
211
|
itemId: z.string().optional().describe("status/sign: o id da peça (vem do list ou do queue)."),
|
|
205
212
|
status: z
|
|
206
213
|
.enum(["fila", "agendado", "postado", "descartado"])
|
|
@@ -273,6 +280,15 @@ export const distributionSchema = z.object({
|
|
|
273
280
|
.nullable()
|
|
274
281
|
.optional()
|
|
275
282
|
.describe("lineage-save: o post do dia da linhagem, ligado ou não, e por quais canais sai. null volta ao padrão."),
|
|
283
|
+
assinatura: z
|
|
284
|
+
.object({
|
|
285
|
+
estilo: z.enum(["casa", "propria", "nenhuma"]),
|
|
286
|
+
marca: z.string().max(24).optional(),
|
|
287
|
+
padrao: z.boolean().optional(),
|
|
288
|
+
})
|
|
289
|
+
.nullable()
|
|
290
|
+
.optional()
|
|
291
|
+
.describe("lineage-save: como a peça da linhagem vai ao ar ASSINADA. estilo casa = sint.fyi/<contaNaCasa dela, ou o dono> no canto (e o fecho de 2s no vídeo); propria = só a `marca` (obrigatória, até 24 caracteres), sem nada da casa, que é o lado adulto (a Aria assina Velourie); nenhuma = a linhagem não assina. padrao=true faz a peça nova dela já nascer assinada. A casa e o dono (sapiens, borderless) não usam marca própria. null volta à da fábrica (casa sem nascer assinada, ou a marca que o código dá: a Aria nasce Velourie); pra forçar o carimbo da casa numa linhagem que a fábrica marca, mande {estilo:\"casa\"}."),
|
|
276
292
|
arquivada: z
|
|
277
293
|
.boolean()
|
|
278
294
|
.optional()
|
|
@@ -281,17 +297,20 @@ export const distributionSchema = z.object({
|
|
|
281
297
|
/** O recado que volta pro agente depois de ligar ou desligar a assinatura. */
|
|
282
298
|
function recadoDaAssinatura(signed, r) {
|
|
283
299
|
if (!signed)
|
|
284
|
-
return "Assinatura desligada:
|
|
285
|
-
|
|
300
|
+
return "Assinatura desligada: a mídia sai como veio do gerador, sem marca.";
|
|
301
|
+
// `midias` é o total desde 24/09/2026 (imagem e vídeo); servidor antigo só
|
|
302
|
+
// mandava `videos`.
|
|
303
|
+
const total = r.midias ?? r.videos;
|
|
304
|
+
const fila = total - r.prontos - r.faltam;
|
|
286
305
|
const partes = [
|
|
287
|
-
"Assinatura ligada:
|
|
288
|
-
r.prontos ===
|
|
289
|
-
? "O carimbo já estava pronto (
|
|
306
|
+
"Assinatura ligada: a mídia vai ao ar com o carimbo da linhagem de quem assina a peça (sint.fyi/<endereço> ou a marca própria dela, ver lineages).",
|
|
307
|
+
r.prontos === total
|
|
308
|
+
? "O carimbo já estava pronto (a mídia tinha sido assinada antes)."
|
|
290
309
|
: fila > 0
|
|
291
|
-
? `${fila}
|
|
310
|
+
? `${fila} mídia(s) na fila do carimbo, uns 30 segundos. Até lá a peça NÃO sai: o botão de postar da tela devolve o motivo.`
|
|
292
311
|
: "",
|
|
293
312
|
r.faltam > 0
|
|
294
|
-
? `A fila carimba 6
|
|
313
|
+
? `A fila carimba 6 por minuto e ${r.faltam} ficaram pra depois; o servidor volta nelas sozinho daqui a um minuto.`
|
|
295
314
|
: "",
|
|
296
315
|
"A peça continua na fila do Distribution: quem posta é a tela.",
|
|
297
316
|
];
|
|
@@ -321,6 +340,7 @@ export async function distribution(args) {
|
|
|
321
340
|
audience: args.audience,
|
|
322
341
|
priceCents: args.priceCents,
|
|
323
342
|
notes: args.notes,
|
|
343
|
+
format: args.format,
|
|
324
344
|
});
|
|
325
345
|
const fila = {
|
|
326
346
|
itemId: r.itemId,
|
|
@@ -457,6 +477,7 @@ export async function distribution(args) {
|
|
|
457
477
|
fichaIds: args.fichaIds,
|
|
458
478
|
contaNaCasa: args.contaNaCasa,
|
|
459
479
|
rotina: args.rotina,
|
|
480
|
+
assinatura: args.assinatura,
|
|
460
481
|
});
|
|
461
482
|
return {
|
|
462
483
|
ok: true,
|
package/dist/tools/gallery.js
CHANGED
|
@@ -63,7 +63,7 @@ export const gallerySchema = z.object({
|
|
|
63
63
|
.positive()
|
|
64
64
|
.max(100)
|
|
65
65
|
.optional()
|
|
66
|
-
.describe("Default 20. Max 100. Só pra action=list."),
|
|
66
|
+
.describe("Default 20. Max 100. Só pra action=list. Sem offset: com filtro de model ou skill a busca varre só as últimas 200 peças. Pra achar o imageId de peça que não é de hoje, use sapiens_reference action=browse bucket=history term=<palavra> (paginado, devolve o imageId) ou sapiens_reference action=resolve handle=img_xxx."),
|
|
67
67
|
model: z
|
|
68
68
|
.string()
|
|
69
69
|
.optional()
|
package/dist/tools/instagram.js
CHANGED
|
@@ -5,7 +5,8 @@ import { need } from "../schema.js";
|
|
|
5
5
|
* sapiens_instagram — o "ManyChat da casa" via MCP. ADMIN-ONLY (requireMcpAdmin
|
|
6
6
|
* no Convex): opera o auto-DM do Instagram da casa (regras de resposta
|
|
7
7
|
* automática, inbox das conversas, resposta manual pela janela de 24h).
|
|
8
|
-
* Espelha
|
|
8
|
+
* Espelha as regras em /experimentos/distribution-workflow?tab=autodm e o inbox
|
|
9
|
+
* em /dashboard/admin/sapiens-leads/instagram; backend em convex/instagramDm.ts.
|
|
9
10
|
*
|
|
10
11
|
* Sub-actions:
|
|
11
12
|
* - rules: lista as regras (keyword, variações, escopo por post, disparos)
|
package/dist/tools/meta.js
CHANGED
|
@@ -430,8 +430,8 @@ export async function meta(args) {
|
|
|
430
430
|
desktopLogin: `${APP_URL}/desktop-login`,
|
|
431
431
|
dashboard: `${APP_URL}/dashboard`,
|
|
432
432
|
adminCuration: `${APP_URL}/dashboard/admin/blog/sapiens-curation`,
|
|
433
|
-
adminPopArticles: `${APP_URL}/dashboard/admin/
|
|
434
|
-
adminPipeline: `${APP_URL}/
|
|
433
|
+
adminPopArticles: `${APP_URL}/dashboard/admin/blog?type=pop-article`,
|
|
434
|
+
adminPipeline: `${APP_URL}/experimentos/content-pipeline`,
|
|
435
435
|
};
|
|
436
436
|
}
|
|
437
437
|
// version: qual versão do sapiens-mcp está rodando AGORA (lida do package.json
|
|
@@ -577,8 +577,9 @@ export async function meta(args) {
|
|
|
577
577
|
}
|
|
578
578
|
const sessionToken = getSessionToken();
|
|
579
579
|
if (args.action === "whoami") {
|
|
580
|
-
// mcpGetMySubscription usa
|
|
581
|
-
//
|
|
580
|
+
// mcpGetMySubscription usa requireMcpSession sem admin (qualquer logado
|
|
581
|
+
// com token de acesso cheio; chave da voz e OAuth de parceira não passam),
|
|
582
|
+
// então whoami funciona pra user E admin e reporta o tier pro Claude.
|
|
582
583
|
const sub = await convexQuery("mcpExtras:mcpGetMySubscription", {
|
|
583
584
|
sessionToken,
|
|
584
585
|
});
|
package/dist/tools/shareDrop.js
CHANGED
|
@@ -8,7 +8,7 @@ import { need } from "../schema.js";
|
|
|
8
8
|
* Sobe um HTML single-file e recebe o link curto sint.fyi/s/<code>. O ponto:
|
|
9
9
|
* PUBLICAR um artefato e depois RE-PUBLICAR no MESMO link quantas vezes quiser
|
|
10
10
|
* (action=update com o code) — edita aqui no Claude, joga pro ar, atualiza o
|
|
11
|
-
* mesmo arquivo. Espelha
|
|
11
|
+
* mesmo arquivo. Espelha o painel /dashboard/admin/share-drop e o CLI
|
|
12
12
|
* share-drop-sync, mas sem admin key: identidade vem do sessionToken.
|
|
13
13
|
*
|
|
14
14
|
* O HTML entra por `html` (string, funciona no stdio E no remoto) ou por
|
package/dist/tools/sintetico.js
CHANGED
|
@@ -260,7 +260,7 @@ export async function sintetico(args) {
|
|
|
260
260
|
});
|
|
261
261
|
return {
|
|
262
262
|
...res,
|
|
263
|
-
note: "Proposta do seu Reflexo (grátis). Pra gerar a cara dele: action=reflexo_generate. Pra CONSAGRAR e criar o Sintético de fato é na web (/experimentos/
|
|
263
|
+
note: "Proposta do seu Reflexo (grátis). Pra gerar a cara dele: action=reflexo_generate. Pra CONSAGRAR e criar o Sintético de fato é na web (/experimentos/identity-workflow, passo final), ato deliberado, fora do MCP.",
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
266
|
// -------- reflexo_generate: gera a imagem do Reflexo (cobra 450) --------
|
package/dist/tools/studios.js
CHANGED
|
@@ -199,7 +199,7 @@ export async function studios(args) {
|
|
|
199
199
|
// tivermos lookup slug-by-id.
|
|
200
200
|
return {
|
|
201
201
|
url: slug ? `${APP}/articles/${slug}` : null,
|
|
202
|
-
admin: `${APP}/
|
|
202
|
+
admin: `${APP}/experimentos/content-pipeline`,
|
|
203
203
|
note: slug
|
|
204
204
|
? "URL pública. Pra ver versões anteriores, use sapiens_pipeline list_versions."
|
|
205
205
|
: "publishableId lookup ainda não suportado v1.3. Passe slug.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.77.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",
|