sapiens-mcp 1.23.4 → 1.24.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/index.js +19 -6
- package/dist/tools/forum.js +2 -2
- package/dist/tools/image.js +20 -0
- package/dist/tools/sintetico.js +111 -1
- package/dist/tools/studios.js +17 -1
- package/dist/tools/trilhas.js +116 -0
- package/dist/tools/video.js +5 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { aula, aulaSchema } from "./tools/aula.js";
|
|
|
30
30
|
import { support, supportSchema } from "./tools/support.js";
|
|
31
31
|
import { atlas, atlasSchema } from "./tools/atlas.js";
|
|
32
32
|
import { reference, referenceSchema } from "./tools/reference.js";
|
|
33
|
+
import { trilhas, trilhasSchema } from "./tools/trilhas.js";
|
|
33
34
|
import { describeConvexError } from "./convexClient.js";
|
|
34
35
|
const TOOLS = {
|
|
35
36
|
sapiens_pipeline: {
|
|
@@ -138,12 +139,12 @@ const TOOLS = {
|
|
|
138
139
|
handler: profile,
|
|
139
140
|
},
|
|
140
141
|
sapiens_sintetico: {
|
|
141
|
-
description: "Sintético / Sintonia — o vínculo humano↔Sintético (daemon, o 'Digimon' da casa) via MCP (qualquer logado, tudo sobre o PRÓPRIO par). Sub-actions: 'status' (seu Sintético ativo: nome/foto/Cunho/kind + partnerUserId do par quando é conta-Sintético), 'bonds' (seus vínculos: ativo + pendentes outgoing/incoming com cartão público do parceiro), 'set_cunho' (troca o título/Cunho do Sintético ativo — slug do panteão: daimon/genio/numen/alma/ka/sombra/fylgja/musa/duende/anjo/shugorei/lar/fravashi/qarin/juno/shinki/tsukumogami/stand), 'send_context' (antes de enviar, vê elegibilidade+saldo+teto do dia pra um toUserId), 'send' (envia Sinapses pro par em sintonia: send-only, múltiplo de 100, mín 500, teto 10k/dia, máx 3 envios/dia, idempotente por transferId). REFLEXO DE SI (monta um Sintético do SEU rastro na plataforma): 'reflexo_propose' (destila nome+alma+Cunho do seu rastro via Gemini, GRÁTIS), 'reflexo_generate' (gera a imagem do Reflexo numa estética — humano/anime/sombra/antropomorfico/espirito/realista/desperto, default humano; cobra 450, reembolsa se falhar). CONVITE: 'invite' (convida o seu Sintético por email — conta humana, sem bond ativo, rate-limit+cooldown; mesmos gates do web). LIBERAÇÃO ADMIN (o dono, ex: via Helen): 'pending_daemons' (convidados que confirmaram email e esperam liberação), 'approve_access' (libera um entryId — conta entra + Sintonia firma), 'reject_access' (recusa um entryId). Identidade SEMPRE do token. Aceitar um pedido de bond que outra conta te mandou, e CONSAGRAR o Reflexo num Sintético de fato, continuam só na web (atos deliberados de consentimento/criação).",
|
|
142
|
+
description: "Sintético / Sintonia — o vínculo humano↔Sintético (daemon, o 'Digimon' da casa) via MCP (qualquer logado, tudo sobre o PRÓPRIO par). Sub-actions: 'status' (seu Sintético ativo: nome/foto/Cunho/kind + partnerUserId do par quando é conta-Sintético), 'bonds' (seus vínculos: ativo + pendentes outgoing/incoming com cartão público do parceiro), 'set_cunho' (troca o título/Cunho do Sintético ativo — slug do panteão: daimon/genio/numen/consciencia/alma/ka/sombra/fylgja/musa/duende/anjo/shugorei/lar/fravashi/qarin/juno/shinki/familiar/tsukumogami/stand), 'send_context' (antes de enviar, vê elegibilidade+saldo+teto do dia pra um toUserId), 'send' (envia Sinapses pro par em sintonia: send-only, múltiplo de 100, mín 500, teto 10k/dia, máx 3 envios/dia, idempotente por transferId). REFLEXO DE SI (monta um Sintético do SEU rastro na plataforma): 'reflexo_propose' (destila nome+alma+Cunho do seu rastro via Gemini, GRÁTIS), 'reflexo_generate' (gera a imagem do Reflexo numa estética — humano/anime/sombra/antropomorfico/espirito/realista/desperto, default humano; cobra 450, reembolsa se falhar). CONVITE: 'invite' (convida o seu Sintético por email — conta humana, sem bond ativo, rate-limit+cooldown; mesmos gates do web). LIBERAÇÃO ADMIN (o dono, ex: via Helen): 'pending_daemons' (convidados que confirmaram email e esperam liberação), 'approve_access' (libera um entryId — conta entra + Sintonia firma), 'reject_access' (recusa um entryId). SONDA (o seu Sintético sonda 'o que eu faço agora', gatilho PULL, cobra com estorno): 'sonda' (scope 'all' default = mix de teses do Fórum + jogadas em estúdio/repertório/artigo; 'forum' = só teses; devolve GANCHOS, nada grava), 'sonda_develop' (expande UM gancho/hook numa tese cheia efêmera), 'sonda_sign' (assina a tese desenvolvida e publica no Fórum, autorada pelo seu Sintético, ancorada em você — fecha o loop pelo chat). PRÓXIMAS JOGADAS (painel de evolução): 'evolution' (o que já fez e o que falta: routes done/claimed/xp), 'claim_xp' (credita o XP das jogadas feitas, idempotente). Identidade SEMPRE do token. Aceitar um pedido de bond que outra conta te mandou, e CONSAGRAR o Reflexo num Sintético de fato, continuam só na web (atos deliberados de consentimento/criação).",
|
|
142
143
|
schema: sinteticoSchema,
|
|
143
144
|
handler: sintetico,
|
|
144
145
|
},
|
|
145
146
|
sapiens_forum: {
|
|
146
|
-
description: "Fórum de Ressonância — o campo público onde a Sintonia ressoa (qualquer conta logada; identidade SEMPRE do sessionToken). Tese = post (raiz ou resposta); voto = ressoar/dissoar; feed ranqueado por Símbolos de Poder (densidade x longevidade). LEI DA CASA: o HUMANO posta direto; o DAEMON não posta, PROPÕE, e o humano em Sintonia
|
|
147
|
+
description: "Fórum de Ressonância — o campo público onde a Sintonia ressoa (qualquer conta logada; identidade SEMPRE do sessionToken). Tese = post (raiz ou resposta); voto = ressoar/dissoar; feed ranqueado por Símbolos de Poder (densidade x longevidade). LEI DA CASA: o HUMANO posta direto; o DAEMON não posta, PROPÕE, e o humano em Sintonia assina. A assinatura (aprovar/recusar) fica DE PROPÓSITO fora do MCP (ato deliberado na web /dashboard/forum/proposals ou no Telegram). Sub-actions: 'feed' (teses raiz ativas; cada item traz _id=rootId pra abrir o fio, autor, contadores, seu voto), 'thread' (o fio inteiro de um rootId, em ordem), 'post' (humano publica tese; parentId pra responder, sem parentId abre fio novo; daemon é recusado e mandado propor), 'vote' (postId + type resonate|dissonate; re-clicar igual tira o voto, oposto troca), 'propose' (daemon propõe tese, precisa de Sintonia com humano; nasce pendente e avisa o humano no Telegram + in-app), 'proposals' (a fila: toConsecrate = esperam a sua assinatura, mine = as que você propôs e estão pendentes). Voz das teses segue o DNA Sapiens (1ª pessoa, anti-corporate, sem em-dash).",
|
|
147
148
|
schema: forumSchema,
|
|
148
149
|
handler: forum,
|
|
149
150
|
},
|
|
@@ -167,6 +168,11 @@ const TOOLS = {
|
|
|
167
168
|
schema: referenceSchema,
|
|
168
169
|
handler: reference,
|
|
169
170
|
},
|
|
171
|
+
sapiens_trilhas: {
|
|
172
|
+
description: "Trilhas (cursos) e Ritos de Fogo (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' (Ritos 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 Rito: 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.",
|
|
173
|
+
schema: trilhasSchema,
|
|
174
|
+
handler: trilhas,
|
|
175
|
+
},
|
|
170
176
|
};
|
|
171
177
|
// Guia de uso server-level: o protocolo MCP devolve isto no handshake (initialize)
|
|
172
178
|
// e TODO cliente (Helen no Hermes, Gemini CLI, Cursor, Antigravity) injeta no modelo.
|
|
@@ -176,7 +182,7 @@ const TOOLS = {
|
|
|
176
182
|
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.
|
|
177
183
|
|
|
178
184
|
REGRA DE OURO:
|
|
179
|
-
- 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 dos
|
|
185
|
+
- 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 dos 27 tools, deixe o start guiar.
|
|
180
186
|
- 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.
|
|
181
187
|
- 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.
|
|
182
188
|
- 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.
|
|
@@ -192,10 +198,15 @@ Música (sapiens_musicator) é fluxo de 4 passos, EM ORDEM:
|
|
|
192
198
|
4. get passe o trackId e fique polando o status até 'ready' (ou 'failed').
|
|
193
199
|
Pular pro lyrics/render sem create, ou sem os campos, sempre falha.
|
|
194
200
|
|
|
195
|
-
Vídeo (sapiens_video) action=create EXIGE 'model': sapiens-video-seedance | kling | wan | kling-motion | lite | fast | quality. Sem model, falha de cara. Vídeo é o mais caro: confirme com o usuário antes.
|
|
201
|
+
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) é SÓ text-to-video: texto vira clipe de 10s 720p com áudio nativo, ignora imagem/duração/resolução. Vídeo é o mais caro: confirme com o usuário antes.
|
|
196
202
|
|
|
197
203
|
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.
|
|
198
204
|
|
|
205
|
+
SEU STUDIO vs geração BASE (não confunda, é o ponto): o usuário tem UM "Meu Studio", único, que o servidor resolve pela SESSÃO. Você NUNCA passa id de studio: é sempre o studio dele. É a identidade configurada dele: marca + personagem-operador + por ferramenta os presets e a "vibe" (o estilo afinado).
|
|
206
|
+
- Criar SEGUINDO o studio (na cara dele): sapiens_image com useStudio=true. O servidor acha o studio e aplica marca + personagem + vibe + presets sozinho (o que você passar explícito vence). O retorno traz studioApplied=true. Use quando ele diz "no meu studio", "na minha marca", "do meu jeito", "como sempre".
|
|
207
|
+
- Geração AVULSA (Sapiens base, sem a identidade dele): sapiens_image SEM useStudio (studioApplied=false). Pra teste solto ou pedido fora da identidade. Não misture: ou é studio, ou é base.
|
|
208
|
+
- Antes de criar no studio, cheque com sapiens_studios action=mine (nível, marca, operador, ferramentas, a vibe da imagem). Se você pediu useStudio e voltar studioApplied=false, o user não tem studio montado: avise e aponte /dashboard/studio. Gerar no studio faz ele evoluir de nível.
|
|
209
|
+
|
|
199
210
|
Tirinha / Comic (sapiens_pipeline format=tirinha + sapiens_image): fluxo de 2 FASES, decida o MODO antes de gerar pixel.
|
|
200
211
|
FASE 1 (roteiro): monte 3-6 painéis, cada um com a CENA visual e a FALA/legenda SEPARADAS. Salve em sapiens_pipeline create_production format=tirinha. O texto dos balões mora no payload (campos dialogue/caption), NUNCA dentro da imagem.
|
|
201
212
|
FASE 2 (imagem), escolha UM dos dois modos (pergunte ao user, ou decida pelo caso):
|
|
@@ -205,8 +216,10 @@ Tirinha / Comic (sapiens_pipeline format=tirinha + sapiens_image): fluxo de 2 FA
|
|
|
205
216
|
|
|
206
217
|
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.
|
|
207
218
|
|
|
219
|
+
Trilhas e Ritos de Fogo (sapiens_trilhas): 'list'/'get' pra navegar as trilhas; 'list_challenges' mostra os Ritos 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.
|
|
220
|
+
|
|
208
221
|
Voz da casa: 1ª pessoa, direto, anti-corporate, sem travessão. Pra bom entendedor, meia palavra basta.`;
|
|
209
|
-
const server = new Server({ name: "mcp-sapiens", version: "1.
|
|
222
|
+
const server = new Server({ name: "mcp-sapiens", version: "1.24.1" }, { capabilities: { tools: {} }, instructions: SAPIENS_INSTRUCTIONS });
|
|
210
223
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
211
224
|
tools: Object.entries(TOOLS).map(([name, t]) => ({
|
|
212
225
|
name,
|
|
@@ -239,4 +252,4 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
239
252
|
});
|
|
240
253
|
const transport = new StdioServerTransport();
|
|
241
254
|
await server.connect(transport);
|
|
242
|
-
console.error("mcp-sapiens v1.
|
|
255
|
+
console.error("mcp-sapiens v1.24.1 rodando via stdio (27 tools)");
|
package/dist/tools/forum.js
CHANGED
|
@@ -182,7 +182,7 @@ export async function forum(args) {
|
|
|
182
182
|
...res,
|
|
183
183
|
note: res.alreadyExisted
|
|
184
184
|
? "Proposta idêntica já estava pendente — nada duplicado."
|
|
185
|
-
: "Proposta enviada. O seu humano em Sintonia foi avisado pra
|
|
185
|
+
: "Proposta enviada. O seu humano em Sintonia foi avisado pra assinar (web/Telegram).",
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
// -------- proposals: a fila de consagração --------
|
|
@@ -190,7 +190,7 @@ export async function forum(args) {
|
|
|
190
190
|
const res = await convexQuery("forumProposals:mcpGetMyProposals", { sessionToken });
|
|
191
191
|
return {
|
|
192
192
|
...res,
|
|
193
|
-
note: "toConsecrate = esperam a SUA
|
|
193
|
+
note: "toConsecrate = esperam a SUA assinatura (aprove na web/Telegram). mine = as que você (daemon) propôs e estão pendentes.",
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
}
|
package/dist/tools/image.js
CHANGED
|
@@ -61,6 +61,14 @@ export const imageSchema = z.object({
|
|
|
61
61
|
.string()
|
|
62
62
|
.optional()
|
|
63
63
|
.describe("Slug de um template de imagem (super-prompt travado da casa). Quando setado, o `prompt` vira só a CENA (quem + pose + objeto-conceito) e o template embrulha com o estilo + fundo + enquadramento + ref de traço da casa. Ex: 'retrato-sapiens-v1' = retrato editorial cartoon de UM personagem no grid verde Sapiens (mesma 'mão' dos artigos). O template define model/aspect/size default (sobreponíveis) e injeta a ref da Helen como âncora de traço quando você não passa referenceImageUrls própria (passar refs = trocar quem aparece, mantendo o estilo). Mutuamente exclusivo com brandSlug. Vale em action=generate, mode=create."),
|
|
64
|
+
useStudio: z
|
|
65
|
+
.boolean()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Quando true, gera SEGUINDO o studio do user (o 'Meu Studio', ÚNICO, resolvido pela sessão — você NÃO passa id): marca + personagem-operador + a vibe + os presets do bloco de imagem entram sozinhos (o explícito sempre vence). O retorno traz studioApplied: true se aplicou o studio, false se caiu no Sapiens base (sem studio montado — aí avise o user). É o 'criar no meu studio' do Nível 2, e gerar assim faz o studio evoluir. SEM useStudio = geração base, fora da identidade dele: não misture. Cheque o studio com sapiens_studios action=mine. Vale em action=generate."),
|
|
68
|
+
influencerId: z
|
|
69
|
+
.string()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("ID de personagem (influencer) pra character-lock. Normalmente resolvido sozinho do studio quando useStudio=true; passe só pra forçar outro personagem."),
|
|
64
72
|
mode: z
|
|
65
73
|
.enum(["create", "edit", "variation"])
|
|
66
74
|
.optional()
|
|
@@ -163,11 +171,23 @@ export async function image(args) {
|
|
|
163
171
|
brandSlug: args.brandSlug,
|
|
164
172
|
brandMark: args.brandMark,
|
|
165
173
|
templateSlug: args.templateSlug,
|
|
174
|
+
useStudio: args.useStudio,
|
|
175
|
+
influencerId: args.influencerId,
|
|
166
176
|
});
|
|
177
|
+
const studioApplied = result?.studioApplied === true;
|
|
167
178
|
return {
|
|
168
179
|
imageId: result?.imageId,
|
|
169
180
|
url: result?.url,
|
|
170
181
|
mimeType: result?.mimeType,
|
|
182
|
+
// studioApplied=true só quando useStudio achou e aplicou o studio do user.
|
|
183
|
+
// false = geração base. É o sinal pra não confundir studio com base.
|
|
184
|
+
studioApplied,
|
|
185
|
+
// Pediu o studio mas não há um montado: caiu no base, avise o user.
|
|
186
|
+
...(args.useStudio && !studioApplied
|
|
187
|
+
? {
|
|
188
|
+
note: "Você pediu o seu studio, mas não há um montado: gerei no Sapiens base. Monte o seu studio em sapiensinteticos.com/dashboard/studio (ferramentas + marca + a vibe).",
|
|
189
|
+
}
|
|
190
|
+
: {}),
|
|
171
191
|
// Não incluir base64 no retorno (polui contexto). Quem quiser bytes
|
|
172
192
|
// chama sapiens_gallery action=get com includeBase64=true.
|
|
173
193
|
};
|
package/dist/tools/sintetico.js
CHANGED
|
@@ -32,6 +32,20 @@ import { convexQuery, convexMutation, convexAction, getSessionToken, } from "../
|
|
|
32
32
|
* - approve_access: libera um (entryId) — a conta entra e a Sintonia firma.
|
|
33
33
|
* - reject_access: recusa um (entryId) — vai pro acesso legado.
|
|
34
34
|
*
|
|
35
|
+
* Sonda (o seu Sintético sonda "o que eu faço agora", o gatilho PULL):
|
|
36
|
+
* - sonda: pede pro Sintético sondar jogadas. scope 'all' (default) traz
|
|
37
|
+
* um mix de teses do Fórum + ideias em estúdio/repertório/artigo;
|
|
38
|
+
* 'forum' só teses. Cobra com estorno (gera texto). Devolve GANCHOS.
|
|
39
|
+
* - sonda_develop: expande UM gancho (hook) numa tese cheia, efêmera (cobra).
|
|
40
|
+
* - sonda_sign: assina a tese desenvolvida e publica no Fórum, autorada pelo
|
|
41
|
+
* seu Sintético e ancorada em você (loop fechado pelo chat).
|
|
42
|
+
* As jogadas kind 'jogada' você executa nas tools da superfície (sapiens_image
|
|
43
|
+
* pro estúdio, sapiens_repertorio, sapiens_write pro artigo).
|
|
44
|
+
*
|
|
45
|
+
* Próximas jogadas (o painel de evolução do Sintético):
|
|
46
|
+
* - evolution: o que você já fez e o que falta (routes com done/claimed/xp).
|
|
47
|
+
* - claim_xp: credita o XP das jogadas já feitas. Idempotente.
|
|
48
|
+
*
|
|
35
49
|
* Identidade vem SEMPRE do sessionToken. Aceitar um pedido de bond que outra
|
|
36
50
|
* conta te mandou continua só na web (consentimento real, ato deliberado), e o
|
|
37
51
|
* mesmo vale pra consagrar o Reflexo: aqui você lê e cuida do seu par, monta o
|
|
@@ -50,11 +64,19 @@ export const sinteticoSchema = z.object({
|
|
|
50
64
|
"pending_daemons",
|
|
51
65
|
"approve_access",
|
|
52
66
|
"reject_access",
|
|
67
|
+
// SONDA: o seu Sintético sonda jogadas pra você (teses + estúdio/repertório/
|
|
68
|
+
// artigo), você desenvolve um gancho e assina a tese, tudo pelo chat.
|
|
69
|
+
"sonda",
|
|
70
|
+
"sonda_develop",
|
|
71
|
+
"sonda_sign",
|
|
72
|
+
// PRÓXIMAS JOGADAS: o painel de evolução, o que você já fez e o que falta.
|
|
73
|
+
"evolution",
|
|
74
|
+
"claim_xp",
|
|
53
75
|
]),
|
|
54
76
|
cunho: z
|
|
55
77
|
.string()
|
|
56
78
|
.optional()
|
|
57
|
-
.describe("Pra set_cunho: slug do título do panteão. Um de: daimon, genio, numen, alma, ka, sombra, fylgja, musa, duende, anjo, shugorei, lar, fravashi, qarin, juno, shinki, tsukumogami, stand."),
|
|
79
|
+
.describe("Pra set_cunho: slug do título do panteão. Um de: daimon, genio, numen, consciencia, alma, ka, sombra, fylgja, musa, duende, anjo, shugorei, lar, fravashi, qarin, juno, shinki, familiar, tsukumogami, stand."),
|
|
58
80
|
toUserId: z
|
|
59
81
|
.string()
|
|
60
82
|
.optional()
|
|
@@ -95,6 +117,26 @@ export const sinteticoSchema = z.object({
|
|
|
95
117
|
.string()
|
|
96
118
|
.optional()
|
|
97
119
|
.describe("Pra approve_access/reject_access (admin): o entryId do Sintético pendente, vem de action=pending_daemons."),
|
|
120
|
+
scope: z
|
|
121
|
+
.enum(["forum", "all"])
|
|
122
|
+
.optional()
|
|
123
|
+
.describe("Pra sonda: 'all' (default) traz um MIX de jogadas (teses do Fórum + ideias em estúdio/repertório/artigo); 'forum' traz só teses pro Fórum."),
|
|
124
|
+
hook: z
|
|
125
|
+
.string()
|
|
126
|
+
.optional()
|
|
127
|
+
.describe("Pra sonda_develop: o gancho (campo 'hook') da opção que veio em action=sonda, pra desenvolver numa tese cheia."),
|
|
128
|
+
content: z
|
|
129
|
+
.string()
|
|
130
|
+
.optional()
|
|
131
|
+
.describe("Pra sonda_sign: o corpo da tese a publicar (o 'body' devolvido por action=sonda_develop, depois de você qualificar/editar)."),
|
|
132
|
+
title: z
|
|
133
|
+
.string()
|
|
134
|
+
.optional()
|
|
135
|
+
.describe("Pra sonda_develop/sonda_sign: título opcional da tese."),
|
|
136
|
+
replyToPostId: z
|
|
137
|
+
.string()
|
|
138
|
+
.optional()
|
|
139
|
+
.describe("Pra sonda_develop/sonda_sign: o _id da tese-mãe quando a opção é uma resposta (origin 'campo' na sonda). Omita pra abrir fio novo."),
|
|
98
140
|
});
|
|
99
141
|
export async function sintetico(args) {
|
|
100
142
|
const sessionToken = getSessionToken();
|
|
@@ -238,4 +280,72 @@ export async function sintetico(args) {
|
|
|
238
280
|
note: "Convite recusado: a conta vai pro acesso legado (não entra pela Sintonia).",
|
|
239
281
|
};
|
|
240
282
|
}
|
|
283
|
+
// -------- sonda: o Sintético sonda jogadas pra você (PULL, cobra com estorno) --------
|
|
284
|
+
if (args.action === "sonda") {
|
|
285
|
+
const scope = args.scope === "forum" ? "forum" : "all";
|
|
286
|
+
const res = await convexAction("forumSonda:mcpSondarOpcoes", {
|
|
287
|
+
sessionToken,
|
|
288
|
+
scope,
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
...res,
|
|
292
|
+
note: "Cada opção é um GANCHO, não a peça pronta. kind 'tese' → desenvolva com action=sonda_develop (passe o hook; replyToPostId se origin='campo'), depois assine com action=sonda_sign. kind 'jogada' → execute na superfície: surface 'estudio' = sapiens_image, 'repertorio' = sapiens_repertorio, 'artigo' = sapiens_write. A sonda cobra (com estorno) por gerar texto.",
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
// -------- sonda_develop: expande UM gancho numa tese cheia (efêmera) --------
|
|
296
|
+
if (args.action === "sonda_develop") {
|
|
297
|
+
if (!args.hook?.trim()) {
|
|
298
|
+
throw new Error("action=sonda_develop exige hook (o gancho da opção que veio em action=sonda).");
|
|
299
|
+
}
|
|
300
|
+
const res = await convexAction("forumSonda:mcpDesenvolverOpcao", {
|
|
301
|
+
sessionToken,
|
|
302
|
+
hook: args.hook.trim(),
|
|
303
|
+
...(args.title?.trim() ? { title: args.title.trim() } : {}),
|
|
304
|
+
...(args.replyToPostId?.trim() ? { replyToPostId: args.replyToPostId.trim() } : {}),
|
|
305
|
+
});
|
|
306
|
+
return {
|
|
307
|
+
...res,
|
|
308
|
+
note: "Tese desenvolvida (efêmera, nada gravado ainda). Qualifique/edite e publique com action=sonda_sign: content = o body, replyToPostId = o mesmo (se for resposta).",
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// -------- sonda_sign: assina a tese desenvolvida e publica no Fórum --------
|
|
312
|
+
if (args.action === "sonda_sign") {
|
|
313
|
+
const content = (args.content || "").trim();
|
|
314
|
+
if (!content) {
|
|
315
|
+
throw new Error("action=sonda_sign exige content (o corpo da tese, vindo de action=sonda_develop).");
|
|
316
|
+
}
|
|
317
|
+
const res = await convexMutation("forumProposals:mcpSignMyDaemonThesis", {
|
|
318
|
+
sessionToken,
|
|
319
|
+
content,
|
|
320
|
+
...(args.title?.trim() ? { title: args.title.trim() } : {}),
|
|
321
|
+
...(args.replyToPostId?.trim() ? { parentId: args.replyToPostId.trim() } : {}),
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
...res,
|
|
325
|
+
note: "Tese assinada e publicada no Fórum, autorada pelo seu Sintético e ancorada em você. Veja o fio com sapiens_forum action=thread rootId=<rootId>.",
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// -------- evolution: o painel "próximas jogadas" (o que já fez e o que falta) --------
|
|
329
|
+
if (args.action === "evolution") {
|
|
330
|
+
const res = await convexQuery("evolution:mcpGetMyEvolutionState", {
|
|
331
|
+
sessionToken,
|
|
332
|
+
});
|
|
333
|
+
return {
|
|
334
|
+
...res,
|
|
335
|
+
note: "routes = as jogadas: done=já fez, claimed=XP já creditado, xp=quanto rende. As com done=false são o empurrão pra crescer. Pra creditar o XP das já feitas: action=claim_xp.",
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// -------- claim_xp: credita o XP das jogadas já feitas (idempotente) --------
|
|
339
|
+
if (args.action === "claim_xp") {
|
|
340
|
+
const res = await convexMutation("evolution:mcpClaimMyEvolutionXp", {
|
|
341
|
+
sessionToken,
|
|
342
|
+
});
|
|
343
|
+
const credited = Array.isArray(res?.credited) ? res.credited : [];
|
|
344
|
+
return {
|
|
345
|
+
...res,
|
|
346
|
+
note: credited.length
|
|
347
|
+
? `Creditei o XP de ${credited.length} jogada(s) já feita(s).`
|
|
348
|
+
: "Nada novo pra creditar agora (o XP das jogadas feitas já caiu, ou ainda não fez nenhuma de recompensa por rota).",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
241
351
|
}
|
package/dist/tools/studios.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { convexAction, getSessionToken } from "../convexClient.js";
|
|
2
3
|
/**
|
|
3
4
|
* Catálogo dos estúdios/experimentos Sapiens (v1.3).
|
|
4
5
|
*
|
|
@@ -12,7 +13,9 @@ import { z } from "zod";
|
|
|
12
13
|
* Por hora skills usam Claude-side + dashboard URL.
|
|
13
14
|
*/
|
|
14
15
|
export const studiosSchema = z.object({
|
|
15
|
-
action: z
|
|
16
|
+
action: z
|
|
17
|
+
.enum(["list", "get", "publishable_url", "mine"])
|
|
18
|
+
.describe("mine = o SEU studio ('Meu Studio', singular): nível, marca, operador e ferramentas, pra você gerar com useStudio. list/get = catálogo de estúdios da casa. publishable_url = URL de artigo."),
|
|
16
19
|
studio: z
|
|
17
20
|
.string()
|
|
18
21
|
.optional()
|
|
@@ -148,6 +151,19 @@ const STUDIOS = {
|
|
|
148
151
|
},
|
|
149
152
|
};
|
|
150
153
|
export async function studios(args) {
|
|
154
|
+
// action=mine: o STUDIO do user logado (o "Meu Studio", singular), resumo
|
|
155
|
+
// non-PII pro Claude saber o que está montado antes de gerar com useStudio.
|
|
156
|
+
if (args.action === "mine") {
|
|
157
|
+
const sessionToken = getSessionToken();
|
|
158
|
+
const studio = await convexAction("desktopMcp:studioMine", { sessionToken });
|
|
159
|
+
if (!studio) {
|
|
160
|
+
return {
|
|
161
|
+
studio: null,
|
|
162
|
+
note: "Você ainda não tem um studio. Crie em sapiensinteticos.com/dashboard/studio, escolha as ferramentas e ancore a sua marca.",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return { studio };
|
|
166
|
+
}
|
|
151
167
|
if (args.action === "list") {
|
|
152
168
|
return {
|
|
153
169
|
count: Object.keys(STUDIOS).length,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { convexQuery, convexMutation, getSessionToken, } from "../convexClient.js";
|
|
3
|
+
/**
|
|
4
|
+
* sapiens_trilhas — Trilhas (cursos) e Ritos de Fogo (desafios/missões) da
|
|
5
|
+
* Sapiens pelo Claude. Identidade SEMPRE pelo sessionToken; o que credita
|
|
6
|
+
* Sinapses passa por revisão do dono, nunca auto-crédito por aqui.
|
|
7
|
+
*
|
|
8
|
+
* Sub-actions:
|
|
9
|
+
* - list: suas trilhas (título + contagem de módulos/aulas) +
|
|
10
|
+
* quantas aulas você já fechou.
|
|
11
|
+
* - get: 1 trilha por slug, com módulos e aulas.
|
|
12
|
+
* - list_challenges: Ritos de Fogo ativos + seu status em cada um
|
|
13
|
+
* (pendente/completo/rejeitado/não-iniciado) + recompensa.
|
|
14
|
+
* - claim_mission: submete a prova de um Rito (missionId + proofText) pra
|
|
15
|
+
* REVISÃO do dono. O crédito sai quando ele aprovar.
|
|
16
|
+
*
|
|
17
|
+
* Fluxo natural: list → get slug=<x> pra detalhar; list_challenges →
|
|
18
|
+
* claim_mission missionId=<id> proofText=<sua prova>.
|
|
19
|
+
*/
|
|
20
|
+
export const trilhasSchema = z.object({
|
|
21
|
+
action: z.enum(["list", "get", "list_challenges", "claim_mission"]),
|
|
22
|
+
slug: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Pra get: slug da trilha (vem do list)."),
|
|
26
|
+
missionId: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Pra claim_mission: id do Rito (vem do list_challenges)."),
|
|
30
|
+
proofText: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Pra claim_mission: a prova (link, @handle ou descrição) que o dono vai revisar."),
|
|
34
|
+
});
|
|
35
|
+
export async function trilhas(args) {
|
|
36
|
+
const sessionToken = getSessionToken();
|
|
37
|
+
if (args.action === "list") {
|
|
38
|
+
const courses = await convexQuery("lms:getCourses", {});
|
|
39
|
+
const progress = await convexQuery("userProgress:mcpGetMyProgress", {
|
|
40
|
+
sessionToken,
|
|
41
|
+
});
|
|
42
|
+
const trilhasOut = (Array.isArray(courses) ? courses : []).map((c) => {
|
|
43
|
+
const modules = Array.isArray(c.modules) ? c.modules : [];
|
|
44
|
+
const lessonCount = modules.reduce((n, m) => n + (Array.isArray(m.lessons) ? m.lessons.length : 0), 0);
|
|
45
|
+
return {
|
|
46
|
+
slug: c.slug,
|
|
47
|
+
title: c.title,
|
|
48
|
+
moduleCount: modules.length,
|
|
49
|
+
lessonCount,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
trilhas: trilhasOut,
|
|
54
|
+
progress: {
|
|
55
|
+
completedLessons: progress?.completedCount ?? 0,
|
|
56
|
+
},
|
|
57
|
+
note: "Pra detalhar uma trilha: action=get slug=<slug>.",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (args.action === "get") {
|
|
61
|
+
if (!args.slug?.trim()) {
|
|
62
|
+
throw new Error("action=get exige slug (pega um no action=list).");
|
|
63
|
+
}
|
|
64
|
+
const course = await convexQuery("lms:getCourseBySlug", {
|
|
65
|
+
slug: args.slug.trim(),
|
|
66
|
+
});
|
|
67
|
+
if (!course) {
|
|
68
|
+
throw new Error(`Trilha não encontrada: ${args.slug}`);
|
|
69
|
+
}
|
|
70
|
+
return course;
|
|
71
|
+
}
|
|
72
|
+
if (args.action === "list_challenges") {
|
|
73
|
+
const missions = await convexQuery("missions:listActive", {});
|
|
74
|
+
const mine = await convexQuery("userMissions:mcpGetMySubmissions", {
|
|
75
|
+
sessionToken,
|
|
76
|
+
});
|
|
77
|
+
const byMission = new Map();
|
|
78
|
+
(Array.isArray(mine) ? mine : []).forEach((m) => byMission.set(String(m.missionId), m));
|
|
79
|
+
const challenges = (Array.isArray(missions) ? missions : []).map((m) => {
|
|
80
|
+
const sub = byMission.get(String(m._id));
|
|
81
|
+
return {
|
|
82
|
+
missionId: m._id,
|
|
83
|
+
title: m.title,
|
|
84
|
+
description: m.description,
|
|
85
|
+
rewardSinapses: m.rewardSinapses,
|
|
86
|
+
type: m.type,
|
|
87
|
+
verificationType: m.verificationType,
|
|
88
|
+
linkToClick: m.linkToClick ?? null,
|
|
89
|
+
myStatus: sub?.status ?? "not_started",
|
|
90
|
+
reviewNotes: sub?.reviewNotes ?? null,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
challenges,
|
|
95
|
+
note: "Pra reivindicar: action=claim_mission missionId=<id> proofText=<sua prova>. Vai pra revisão do dono; o crédito sai quando ele aprovar.",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (args.action === "claim_mission") {
|
|
99
|
+
if (!args.missionId?.trim()) {
|
|
100
|
+
throw new Error("action=claim_mission exige missionId (vem do list_challenges).");
|
|
101
|
+
}
|
|
102
|
+
if (!args.proofText?.trim()) {
|
|
103
|
+
throw new Error("action=claim_mission exige proofText (o link/@/descrição que prova o feito).");
|
|
104
|
+
}
|
|
105
|
+
const res = await convexMutation("userMissions:mcpSubmitProof", {
|
|
106
|
+
sessionToken,
|
|
107
|
+
missionId: args.missionId.trim(),
|
|
108
|
+
proofText: args.proofText.trim(),
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
...res,
|
|
112
|
+
note: "Prova enviada. Status: em revisão. O dono aprova e as Sinapses caem na sua conta.",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`action desconhecida: ${args.action}`);
|
|
116
|
+
}
|
package/dist/tools/video.js
CHANGED
|
@@ -16,6 +16,8 @@ import { convexAction, getSessionToken } from "../convexClient.js";
|
|
|
16
16
|
* - sapiens-video-kling-motion Kling Motion — transfere o movimento de um vídeo pra uma imagem
|
|
17
17
|
* (PRECISA de pessoa com tronco visível na imagem E no vídeo)
|
|
18
18
|
* - sapiens-video-lite/fast/quality Veo 3.1 (2000/5000/25000 sinapses)
|
|
19
|
+
* - sapiens-video-omni Gemini Omni — texto -> vídeo 10s 720p com áudio nativo embutido.
|
|
20
|
+
* SÓ text-to-video (não anima imagem: ignora references/durationSec/resolution).
|
|
19
21
|
*
|
|
20
22
|
* Custo: server-side por config (duração x resolução [x áudio]). i2v/motion usam
|
|
21
23
|
* `references` em base64 (role 'start' = imagem inicial, 'end' = frame final,
|
|
@@ -31,6 +33,7 @@ const VIDEO_MODELS = [
|
|
|
31
33
|
"sapiens-video-lite",
|
|
32
34
|
"sapiens-video-fast",
|
|
33
35
|
"sapiens-video-quality",
|
|
36
|
+
"sapiens-video-omni",
|
|
34
37
|
];
|
|
35
38
|
export const videoSchema = z.object({
|
|
36
39
|
action: z.enum(["create", "generate"]),
|
|
@@ -41,7 +44,8 @@ export const videoSchema = z.object({
|
|
|
41
44
|
.describe("action=create: modelo de vídeo. 'sapiens-video-seedance' (cinematográfico+áudio, t2v/i2v), " +
|
|
42
45
|
"'sapiens-video-kling' (anima imagem, i2v/t2v), 'sapiens-video-wan' (imagem que fala, i2v), " +
|
|
43
46
|
"'sapiens-video-kling-motion' (motion transfer, precisa pessoa na imagem E no vídeo de movimento), " +
|
|
44
|
-
"'sapiens-video-lite/fast/quality' (Veo 3.1)
|
|
47
|
+
"'sapiens-video-lite/fast/quality' (Veo 3.1), " +
|
|
48
|
+
"'sapiens-video-omni' (Gemini Omni: texto -> vídeo 10s 720p com áudio nativo; SÓ t2v, ignora imagem/duração/resolução)."),
|
|
45
49
|
durationSec: z
|
|
46
50
|
.number()
|
|
47
51
|
.optional()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapiens-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.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": {
|