sapiens-mcp 1.26.4 → 1.27.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/convexClient.js +14 -0
- package/dist/index.js +7 -7
- package/dist/tools/instagram.js +22 -2
- package/dist/tools/studios.js +2 -1
- package/dist/tools/trilhas.js +8 -7
- package/dist/tools/video.js +43 -2
- package/package.json +1 -1
package/dist/convexClient.js
CHANGED
|
@@ -45,6 +45,12 @@ function loadLocalEnv() {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
// Override de identidade INJETADO pelo processo pai (ex: o house-hermes spawna o
|
|
49
|
+
// MCP com SAPIENS_SESSION_TOKEN = o token da daemon daquela conversa). Capturado
|
|
50
|
+
// AQUI, ANTES do loadLocalEnv, de propósito: só vale um token vindo do env REAL
|
|
51
|
+
// do spawn, não um que caísse de um .env.local (que reviveria o bug do token
|
|
52
|
+
// velho sombrando login). Ver getSessionToken.
|
|
53
|
+
const INJECTED_SESSION_TOKEN = process.env.SAPIENS_SESSION_TOKEN;
|
|
48
54
|
loadLocalEnv();
|
|
49
55
|
/**
|
|
50
56
|
* Lê session token do plugin Claude Code (state local). Esse arquivo é criado
|
|
@@ -139,6 +145,14 @@ function readStoredSessionToken() {
|
|
|
139
145
|
return null;
|
|
140
146
|
}
|
|
141
147
|
export function getSessionToken() {
|
|
148
|
+
// Prioridade 0: token INJETADO pelo processo pai (SAPIENS_SESSION_TOKEN no env
|
|
149
|
+
// do spawn). É o mecanismo do house-hermes pra rodar o MCP na conta de UMA
|
|
150
|
+
// daemon específica por conversa, sem depender do login em disco da máquina.
|
|
151
|
+
// Capturado antes do loadLocalEnv (ver topo do arquivo), então só um env real
|
|
152
|
+
// conta, nunca um .env.local. Vence tudo de propósito: é escolha explícita.
|
|
153
|
+
if (INJECTED_SESSION_TOKEN && INJECTED_SESSION_TOKEN.length > 8) {
|
|
154
|
+
return INJECTED_SESSION_TOKEN;
|
|
155
|
+
}
|
|
142
156
|
// Ordem de prioridade (mudou em v1.9.1 — ver POR QUE abaixo):
|
|
143
157
|
// 1. store local do login do MCP (~/.sapiens-mcp/session.json) — o que
|
|
144
158
|
// `sapiens_meta action=login` acabou de salvar. Fonte canônica.
|
package/dist/index.js
CHANGED
|
@@ -150,7 +150,7 @@ const TOOLS = {
|
|
|
150
150
|
handler: forum,
|
|
151
151
|
},
|
|
152
152
|
sapiens_instagram: {
|
|
153
|
-
description: "Auto-DM do Instagram da casa (o 'ManyChat próprio') — ADMIN-ONLY (dono). Quem manda DM ou comenta keyword num post do @sapiensinteticos recebe resposta automática; aqui você OPERA esse motor. Sub-actions: 'rules' (lista regras: keyword, resposta, variações, eco público, escopo por post, disparos), 'rule_upsert' (cria/edita regra; ruleId presente = edita; keyword+reply obrigatórios fora do fallback; replyVariants/echoVariants rodam em round-robin pra não repetir; mediaId escopa a regra num post; isFallback responde DM sem keyword 1x/24h por pessoa), 'rule_delete' (apaga por ruleId), 'inbox' (conversas recentes; cada uma com canReply = janela de 24h da Meta aberta ou não), 'thread' (mensagens de uma conversa por igUserId), 'send' (responde na mão pela janela de 24h; fora dela a Meta recusa).
|
|
153
|
+
description: "Auto-DM do Instagram da casa (o 'ManyChat próprio') — ADMIN-ONLY (dono). Quem manda DM ou comenta keyword num post do @sapiensinteticos recebe resposta automática; aqui você OPERA esse motor. Sub-actions: 'rules' (lista regras: keyword+sinônimos, matchMode, trigger, resposta, variações, eco público, escopo por post, disparos), 'rule_upsert' (cria/edita regra; ruleId presente = edita; keyword (+keywords sinônimos) + reply obrigatórios fora do fallback; matchMode contains|exact|starts; trigger dm|comment|story|all; replyVariants/echoVariants rodam em round-robin pra não repetir; mediaId escopa a regra num post — pegue ids reais com action=posts; isFallback responde DM sem keyword 1x/24h por pessoa), 'rule_delete' (apaga por ruleId), 'posts' (posts recentes da conta: id+caption+thumb, pra usar o id em mediaId), 'inbox' (conversas recentes; cada uma com canReply = janela de 24h da Meta aberta ou não), 'thread' (mensagens de uma conversa por igUserId), 'send' (responde na mão pela janela de 24h; fora dela a Meta recusa). Eco público opcional no comentário ('te respondi no direct!'). Limites da API: não dá pra iniciar conversa, só reagir; janela de 24h pra responder DM.",
|
|
154
154
|
schema: instagramSchema,
|
|
155
155
|
handler: instagram,
|
|
156
156
|
},
|
|
@@ -175,7 +175,7 @@ const TOOLS = {
|
|
|
175
175
|
handler: reference,
|
|
176
176
|
},
|
|
177
177
|
sapiens_trilhas: {
|
|
178
|
-
description: "Trilhas (cursos) e
|
|
178
|
+
description: "Trilhas (cursos) e Desafios (missões) da Sapiens pelo Claude. Identidade SEMPRE pelo sessionToken. Sub-actions: 'list' (suas trilhas: título + nº de módulos/aulas + quantas aulas você já fechou), 'get' (1 trilha por slug, com módulos e aulas — o slug vem do list), 'list_challenges' (Desafios ativos + seu status em cada: not_started|pending_review|completed|rejected, recompensa em Sinapses, link da ação), 'claim_mission' (submete a prova de um Desafio: missionId + proofText). O claim manda a prova pra REVISÃO do dono — o crédito em Sinapses só cai quando ele aprovar, nunca auto-credita por aqui. Fluxo: list → get; list_challenges → claim_mission.",
|
|
179
179
|
schema: trilhasSchema,
|
|
180
180
|
handler: trilhas,
|
|
181
181
|
},
|
|
@@ -188,7 +188,7 @@ const TOOLS = {
|
|
|
188
188
|
const SAPIENS_INSTRUCTIONS = `Você opera o Sapiens Sintéticos (sapiensinteticos.com) NA CONTA de um usuário logado. Cada tool age de verdade na conta dele e muitas COBRAM Sinapses (o crédito da casa). Aja como operador, não no chute.
|
|
189
189
|
|
|
190
190
|
REGRA DE OURO:
|
|
191
|
-
- PRIMEIRO CONTATO ou "o que você faz?"/"como começo?"/"o que dá pra fazer?": chame sapiens_meta action=start e MOSTRE o resultado na sua voz. Sem login, ele ensina a conectar; logado, traz saldo + primeiros poderes com exemplos. É a porta de entrada: não despeje a lista
|
|
191
|
+
- PRIMEIRO CONTATO ou "o que você faz?"/"como começo?"/"o que dá pra fazer?": chame sapiens_meta action=start e MOSTRE o resultado na sua voz. Sem login, ele ensina a conectar; logado, traz saldo + primeiros poderes com exemplos. É a porta de entrada: não despeje a lista inteira de tools, deixe o start guiar.
|
|
192
192
|
- LOGO APÓS UM LOGIN BEM-SUCEDIDO (action=login retornou ok): chame action=start na sequência e mostre a porta de entrada. O recém-chegado não sabe o que pedir; não o deixe na tela em branco, guie a primeira jogada sem ele precisar perguntar.
|
|
193
193
|
- Se um tool voltar erro de validação ("exige X", "falta Y"), LEIA o erro e refaça a chamada COM o que falta. NUNCA repita igual a chamada que falhou: 3 falhas seguidas no mesmo tool fazem o cliente marcar o servidor como "unreachable" por ~56s (disjuntor anti-loop). Aí parece que "o MCP caiu", quando foi só argumento faltando.
|
|
194
194
|
- Antes de gerar algo caro (imagem/música/vídeo), cheque saldo: sapiens_meta action=credits (ou subscription). Saldo baixo, avise o usuário antes.
|
|
@@ -204,7 +204,7 @@ Música (sapiens_musicator) é fluxo de 4 passos, EM ORDEM:
|
|
|
204
204
|
4. get passe o trackId e fique polando o status até 'ready' (ou 'failed').
|
|
205
205
|
Pular pro lyrics/render sem create, ou sem os campos, sempre falha.
|
|
206
206
|
|
|
207
|
-
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality | omni. Sem model, falha de cara. O 'omni' (Gemini Omni) gera clipe de 10s 720p com áudio nativo a partir de TEXTO (não aceita imagem/vídeo do user, ignora duração/resolução) e EDITA os próprios vídeos: passe editOfImageId com o imageId de um vídeo Omni já gerado e o prompt vira instrução de edição sobre a MESMA cena (troca item/personagem, preserva câmera e ambiente; cada edição debita como geração nova). É o caminho pra variações com continuidade: gera a base uma vez, edita N vezes. Vídeo é o mais caro: confirme com o usuário antes. Vitrine dos demos (sem custo): sapiens_video action=demos lista seus demo films com slug; action=showcase (slug + showcase=true/false + showcaseTag + showcaseOrder) cura o mini-cinema da /conectar-claude. FILMES DA CASA (Estúdio de Vídeo, tela /experimentos/films): são OUTRA coisa, três kinds na tabela videoSpecs: demo (UI clonada + câmera), aula-tour (telas reais + narração) e essay (fita-ensaio abstrata: partícula/tinta vira símbolo, com a logo explodindo no fim; narração da casa OPCIONAL, sai em 16:9 ou 9:16 vertical, e o filme final é limpo, sem rótulos de produção). Eles NÃO são gerados por este MCP: o user monta o spec na tela e um agente local (Claude Code, skill /film) produz o mp4 no repo da casa. Se o user pedir 'fita-ensaio' ou 'demo film' aqui, aponte pra tela e pro agente local.
|
|
207
|
+
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality | omni. Sem model, falha de cara. O 'omni' (Gemini Omni) gera clipe de 10s 720p com áudio nativo a partir de TEXTO (não aceita imagem/vídeo do user, ignora duração/resolução) e EDITA os próprios vídeos: passe editOfImageId com o imageId de um vídeo Omni já gerado e o prompt vira instrução de edição sobre a MESMA cena (troca item/personagem, preserva câmera e ambiente; cada edição debita como geração nova). É o caminho pra variações com continuidade: gera a base uma vez, edita N vezes. Vídeo é o mais caro: confirme com o usuário antes. action=shadows (ADMIN, 200 Sinapses/segundo, refund na falha): passa videoUrl (URL pública) + title (+ durationSec se souber, pra cobrar proporcional; sem ela, flat ~2000) e o servidor extrai a SOMBRA (mapa de profundidade) do vídeo e guarda no Acervo (Corpo) como deepshadow reutilizável (driving pro Shot Mimic/Kling Motion). Vitrine dos demos (sem custo): sapiens_video action=demos lista seus demo films com slug; action=showcase (slug + showcase=true/false + showcaseTag + showcaseOrder) cura o mini-cinema da /conectar-claude. FILMES DA CASA (Estúdio de Vídeo, tela /experimentos/films): são OUTRA coisa, três kinds na tabela videoSpecs: demo (UI clonada + câmera), aula-tour (telas reais + narração) e essay (fita-ensaio abstrata: partícula/tinta vira símbolo, com a logo explodindo no fim; narração da casa OPCIONAL, sai em 16:9 ou 9:16 vertical, e o filme final é limpo, sem rótulos de produção). Eles NÃO são gerados por este MCP: o user monta o spec na tela e um agente local (Claude Code, skill /film) produz o mp4 no repo da casa. Se o user pedir 'fita-ensaio' ou 'demo film' aqui, aponte pra tela e pro agente local.
|
|
208
208
|
|
|
209
209
|
Imagem (sapiens_image) action=generate: prompt + model + aspectRatio. Referência via referenceImageUrls (galeria/Acervo/personagens) e/ou sourceImageIds. templateSlug aplica um super-prompt travado da casa.
|
|
210
210
|
|
|
@@ -223,10 +223,10 @@ Tirinha / Comic (sapiens_pipeline format=tirinha + sapiens_image): fluxo de 2 FA
|
|
|
223
223
|
|
|
224
224
|
Mídia no Fórum (PADRÃO, faça sempre assim): a peça vai EMBEDADA num card estruturado, nunca como "vai ouvir/ver noutro lugar". Música publicada (sapiens_musicator action=publish) já cria a tese no Fórum com a faixa tocável, não escreva "tá no Acervo, ouça lá". Pra anexar mídia a uma tese sua: sapiens_forum action=post com mediaTrackId (faixa pronta sua → card de música) OU mediaUrl + mediaKind (video|image; arquivo da casa, ou link YouTube/Vimeo pra vídeo). NÃO cole a URL da mídia no corpo da tese, use o campo: o corpo é só texto.
|
|
225
225
|
|
|
226
|
-
Trilhas e
|
|
226
|
+
Trilhas e Desafios (sapiens_trilhas): 'list'/'get' pra navegar as trilhas; 'list_challenges' mostra os Desafios ativos + seu status; 'claim_mission' (missionId + proofText) envia a prova pra revisão do dono — o crédito em Sinapses sai na aprovação dele, não na hora. Não prometa Sinapse na hora do claim.
|
|
227
227
|
|
|
228
228
|
Voz da casa: 1ª pessoa, direto, anti-corporate, sem travessão. Pra bom entendedor, meia palavra basta.`;
|
|
229
|
-
const server = new Server({ name: "mcp-sapiens", version: "1.
|
|
229
|
+
const server = new Server({ name: "mcp-sapiens", version: "1.27.1" }, { capabilities: { tools: {} }, instructions: SAPIENS_INSTRUCTIONS });
|
|
230
230
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
231
231
|
tools: Object.entries(TOOLS).map(([name, t]) => ({
|
|
232
232
|
name,
|
|
@@ -259,4 +259,4 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
259
259
|
});
|
|
260
260
|
const transport = new StdioServerTransport();
|
|
261
261
|
await server.connect(transport);
|
|
262
|
-
console.error(
|
|
262
|
+
console.error(`mcp-sapiens v1.27.1 rodando via stdio (${Object.keys(TOOLS).length} tools)`);
|
package/dist/tools/instagram.js
CHANGED
|
@@ -15,12 +15,24 @@ import { convexAction, convexMutation, convexQuery, getSessionToken } from "../c
|
|
|
15
15
|
* - send: responde uma conversa na mão (só com a janela aberta)
|
|
16
16
|
*/
|
|
17
17
|
export const instagramSchema = z.object({
|
|
18
|
-
action: z.enum(["rules", "rule_upsert", "rule_delete", "inbox", "thread", "send"]),
|
|
18
|
+
action: z.enum(["rules", "rule_upsert", "rule_delete", "inbox", "thread", "send", "posts"]),
|
|
19
19
|
ruleId: z.string().optional().describe("Id da regra (rule_upsert pra editar, rule_delete)."),
|
|
20
20
|
keyword: z
|
|
21
21
|
.string()
|
|
22
22
|
.optional()
|
|
23
|
-
.describe("Keyword da regra (substring case-insensitive
|
|
23
|
+
.describe("Keyword principal da regra (substring case-insensitive por padrão). Obrigatória em regra não-fallback (ou use keywords)."),
|
|
24
|
+
keywords: z
|
|
25
|
+
.array(z.string())
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Sinônimos: a regra casa se QUALQUER um (keyword + keywords) bater. Ex: [site, url]."),
|
|
28
|
+
matchMode: z
|
|
29
|
+
.enum(["contains", "exact", "starts"])
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Como a keyword casa: contains (substring, default) / exact (palavra inteira) / starts (texto começa com)."),
|
|
32
|
+
trigger: z
|
|
33
|
+
.enum(["dm", "comment", "story", "all"])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("O que dispara: dm / comment / story (resposta a story) / all (default: DM e comentário)."),
|
|
24
36
|
reply: z.string().optional().describe("Resposta na DM (obrigatória no rule_upsert)."),
|
|
25
37
|
replyVariants: z
|
|
26
38
|
.array(z.string())
|
|
@@ -62,6 +74,9 @@ export async function instagram(args) {
|
|
|
62
74
|
sessionToken,
|
|
63
75
|
ruleId: args.ruleId,
|
|
64
76
|
keyword: args.keyword,
|
|
77
|
+
keywords: args.keywords,
|
|
78
|
+
matchMode: args.matchMode,
|
|
79
|
+
trigger: args.trigger,
|
|
65
80
|
reply,
|
|
66
81
|
replyVariants: args.replyVariants,
|
|
67
82
|
commentEcho: args.commentEcho,
|
|
@@ -94,5 +109,10 @@ export async function instagram(args) {
|
|
|
94
109
|
igUserId: need(args.igUserId, "igUserId"),
|
|
95
110
|
text: need(args.text, "text"),
|
|
96
111
|
});
|
|
112
|
+
case "posts":
|
|
113
|
+
return await convexAction("instagramDm:mcpListMedia", {
|
|
114
|
+
sessionToken,
|
|
115
|
+
limit: args.limit,
|
|
116
|
+
});
|
|
97
117
|
}
|
|
98
118
|
}
|
package/dist/tools/studios.js
CHANGED
|
@@ -138,7 +138,8 @@ const STUDIOS = {
|
|
|
138
138
|
comunidade: {
|
|
139
139
|
name: "Comunidade Sapiens",
|
|
140
140
|
description: "Chat compartilhado entre assinantes/alumni. Posts com voz Sapiens.",
|
|
141
|
-
|
|
141
|
+
// /comunidade (sem /dashboard) hoje é 308 pro Acervo; o chat vive aqui.
|
|
142
|
+
url: `${APP}/dashboard/comunidade`,
|
|
142
143
|
status: "stable",
|
|
143
144
|
tags: ["chat", "comunidade"],
|
|
144
145
|
convex: "communityChat",
|
package/dist/tools/trilhas.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { convexQuery, convexMutation, getSessionToken, } from "../convexClient.js";
|
|
3
3
|
/**
|
|
4
|
-
* sapiens_trilhas — Trilhas (cursos) e
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* sapiens_trilhas — Trilhas (cursos) e Desafios (missões) da Sapiens pelo
|
|
5
|
+
* Claude. Identidade SEMPRE pelo sessionToken; o que credita Sinapses passa
|
|
6
|
+
* por revisão do dono, nunca auto-crédito por aqui. ("Ritos de Fogo" é o nome
|
|
7
|
+
* antigo dos Desafios; saiu no saneamento de naming de jul/2026.)
|
|
7
8
|
*
|
|
8
9
|
* Sub-actions:
|
|
9
10
|
* - list: suas trilhas (título + contagem de módulos/aulas) +
|
|
10
11
|
* quantas aulas você já fechou.
|
|
11
12
|
* - get: 1 trilha por slug, com módulos e aulas.
|
|
12
|
-
* - list_challenges:
|
|
13
|
+
* - list_challenges: Desafios ativos + seu status em cada um
|
|
13
14
|
* (pendente/completo/rejeitado/não-iniciado) + recompensa.
|
|
14
|
-
* - claim_mission: submete a prova de um
|
|
15
|
-
* REVISÃO do dono. O crédito sai quando ele aprovar.
|
|
15
|
+
* - claim_mission: submete a prova de um Desafio (missionId + proofText)
|
|
16
|
+
* pra REVISÃO do dono. O crédito sai quando ele aprovar.
|
|
16
17
|
*
|
|
17
18
|
* Fluxo natural: list → get slug=<x> pra detalhar; list_challenges →
|
|
18
19
|
* claim_mission missionId=<id> proofText=<sua prova>.
|
|
@@ -26,7 +27,7 @@ export const trilhasSchema = z.object({
|
|
|
26
27
|
missionId: z
|
|
27
28
|
.string()
|
|
28
29
|
.optional()
|
|
29
|
-
.describe("Pra claim_mission: id do
|
|
30
|
+
.describe("Pra claim_mission: id do Desafio (vem do list_challenges)."),
|
|
30
31
|
proofText: z
|
|
31
32
|
.string()
|
|
32
33
|
.optional()
|
package/dist/tools/video.js
CHANGED
|
@@ -13,6 +13,13 @@ import { convexAction, convexQuery, convexMutation, getSessionToken } from "../c
|
|
|
13
13
|
* - showcase: põe/tira um demo film (por slug) da vitrine /conectar-claude, com
|
|
14
14
|
* chip (showcaseTag) e ordem (showcaseOrder). Só entra na vitrine
|
|
15
15
|
* pública se for a conta da casa. Sem custo.
|
|
16
|
+
* - shadows: (ADMIN) extrai a SOMBRA (mapa de profundidade) de um vídeo por
|
|
17
|
+
* URL e guarda no Acervo (Corpo) como deepshadow reutilizável.
|
|
18
|
+
* 200 Sinapses/segundo (durationSec; sem ela, flat 2000). Refund se falhar.
|
|
19
|
+
* - shadows-list: (ADMIN) lista o banco de motion (deepshadows + guias de corpo)
|
|
20
|
+
* com as duas views por ficha: url = sombra pura (driving pros
|
|
21
|
+
* geradores) e skeletonUrl = a soma (sombras + esqueleto, preview
|
|
22
|
+
* humano que separa personagem de objeto). Sem custo.
|
|
16
23
|
*
|
|
17
24
|
* Modelos (action=create):
|
|
18
25
|
* - sapiens-video-seedance Seedance 2.0 — cena com áudio nativo, 4-15s, 480/720/1080p (t2v/i2v)
|
|
@@ -46,7 +53,20 @@ const VIDEO_MODELS = [
|
|
|
46
53
|
"sapiens-video-omni",
|
|
47
54
|
];
|
|
48
55
|
export const videoSchema = z.object({
|
|
49
|
-
action: z.enum(["create", "generate", "demos", "showcase"]),
|
|
56
|
+
action: z.enum(["create", "generate", "demos", "showcase", "shadows", "shadows-list"]),
|
|
57
|
+
// --- action=shadows (deepshadows: extrai o mapa de profundidade de um vídeo) ---
|
|
58
|
+
videoUrl: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("action=shadows: URL pública (http/https) do vídeo-fonte. O servidor extrai a SOMBRA (depth) e guarda no Acervo (Corpo). ADMIN, 200 Sinapses/segundo (refund na falha)."),
|
|
62
|
+
title: z
|
|
63
|
+
.string()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("action=shadows: nome do deepshadow (vira o slug no Acervo; re-extrair o mesmo título sobrescreve). Mín. 3 chars."),
|
|
66
|
+
search: z
|
|
67
|
+
.string()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe("action=shadows-list: filtro de busca opcional (título/tags). Sem ele, lista o banco inteiro (até 300). Cada item traz url (sombra pura, driving) e skeletonUrl (soma com esqueleto, preview humano) quando existe."),
|
|
50
70
|
// --- action=showcase (curadoria da vitrine /conectar-claude) ---
|
|
51
71
|
slug: z
|
|
52
72
|
.string()
|
|
@@ -78,7 +98,8 @@ export const videoSchema = z.object({
|
|
|
78
98
|
.number()
|
|
79
99
|
.optional()
|
|
80
100
|
.describe("action=create (modelos WaveSpeed): duração em segundos. Seedance/Shot Mimic 4-15, Kling 3-15, WAN 5/10. " +
|
|
81
|
-
"Sem isso usa a config mais barata. O preço escala com a duração."
|
|
101
|
+
"Sem isso usa a config mais barata. O preço escala com a duração. " +
|
|
102
|
+
"action=shadows: duração do vídeo-fonte, se souber (cobra 200/s; sem ela, flat ~2000)."),
|
|
82
103
|
resolution: z
|
|
83
104
|
.enum(["480p", "720p", "1080p"])
|
|
84
105
|
.optional()
|
|
@@ -181,6 +202,26 @@ export async function video(args) {
|
|
|
181
202
|
editOfImageId: args.editOfImageId,
|
|
182
203
|
});
|
|
183
204
|
}
|
|
205
|
+
if (args.action === "shadows") {
|
|
206
|
+
if (!args.videoUrl) {
|
|
207
|
+
throw new Error("action=shadows exige videoUrl (URL pública do vídeo-fonte).");
|
|
208
|
+
}
|
|
209
|
+
if (!args.title || args.title.trim().length < 3) {
|
|
210
|
+
throw new Error("action=shadows exige title (mín. 3 chars; vira o slug do deepshadow).");
|
|
211
|
+
}
|
|
212
|
+
return await convexAction("mcpExtrasActions:mcpExtractShadows", {
|
|
213
|
+
sessionToken,
|
|
214
|
+
videoUrl: args.videoUrl,
|
|
215
|
+
title: args.title,
|
|
216
|
+
durationSec: args.durationSec,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (args.action === "shadows-list") {
|
|
220
|
+
return await convexAction("mcpExtrasActions:mcpListShadows", {
|
|
221
|
+
sessionToken,
|
|
222
|
+
search: args.search,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
184
225
|
if (args.action === "generate") {
|
|
185
226
|
if (!args.imageId) {
|
|
186
227
|
throw new Error("action=generate exige imageId (vídeo já criado no site).");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.1",
|
|
4
4
|
"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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|