beplus-mcp 0.11.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/index.js +113 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -157,7 +157,15 @@ var BeplusClient = class {
157
157
  return this.request("DELETE", `/generations/${id}`);
158
158
  }
159
159
  listGenerations(query) {
160
- return this.request("GET", "/generations", { query });
160
+ return this.request("GET", "/generations", {
161
+ query: {
162
+ limit: query.limit,
163
+ offset: query.offset,
164
+ // Only send when true — the backend treats truthy as "constrain".
165
+ favorite: query.favorite ? "true" : void 0,
166
+ approved: query.approved ? "true" : void 0
167
+ }
168
+ });
161
169
  }
162
170
  tts(body) {
163
171
  return this.request("POST", "/tts", { body, timeoutMs: 9e4 });
@@ -181,7 +189,18 @@ var BeplusClient = class {
181
189
  return this.request("POST", "/analyze-media", { body, timeoutMs: 3e5 });
182
190
  }
183
191
  searchCalls(query) {
184
- return this.request("GET", "/calls", { query });
192
+ return this.request("GET", "/calls", {
193
+ query: {
194
+ query: query.query,
195
+ project: query.project,
196
+ client: query.client,
197
+ company: query.company,
198
+ visibility: query.visibility,
199
+ speaker: query.speaker,
200
+ mine: query.mine ? "true" : void 0,
201
+ limit: query.limit
202
+ }
203
+ });
185
204
  }
186
205
  getCall(id) {
187
206
  return this.request("GET", `/calls/${id}`);
@@ -363,6 +382,25 @@ function logError(...args) {
363
382
  }
364
383
 
365
384
  // src/format.ts
385
+ function fmtResetDate(iso) {
386
+ const [, m, d] = iso.split("-");
387
+ return d && m ? `${d}/${m}` : iso;
388
+ }
389
+ function weeklyAllowanceLine(wa) {
390
+ if (!wa || !wa.enabled) return "";
391
+ if (wa.unlimited) return "\u267E\uFE0F Limite semanal: ilimitado (sua conta \xE9 isenta).";
392
+ const pct = wa.percentUsed;
393
+ const icon = pct >= 100 ? "\u{1F6D1}" : pct >= wa.warnThresholdPercent ? "\u26A0\uFE0F" : "\u{1F4CA}";
394
+ let line = `${icon} Limite semanal: ${pct}% usado \xB7 ${wa.remaining} de ${wa.quota} restantes`;
395
+ if (pct >= 100) {
396
+ line += `
397
+ \u{1F6D1} Limite semanal atingido \u2014 reseta em ${fmtResetDate(wa.periodEnd)}.`;
398
+ } else if (pct >= wa.warnThresholdPercent) {
399
+ line += `
400
+ \u26A0\uFE0F Seu limite semanal est\xE1 acabando \u2014 reseta em ${fmtResetDate(wa.periodEnd)}.`;
401
+ }
402
+ return line;
403
+ }
366
404
  function textResult(s) {
367
405
  return { content: [{ type: "text", text: s }] };
368
406
  }
@@ -390,6 +428,9 @@ ${footer}`;
390
428
  footer = footer ? `${proj}
391
429
  ${footer}` : proj;
392
430
  }
431
+ const wa = weeklyAllowanceLine(start.weekly_allowance);
432
+ if (wa) footer = footer ? `${footer}
433
+ ${wa}` : wa;
393
434
  return footer;
394
435
  }
395
436
  function outputUrls(status) {
@@ -497,6 +538,22 @@ var DEFAULTS = {
497
538
  // src/tools/generation.ts
498
539
  var IMAGE_BUDGET_MS = 9e4;
499
540
  var VIDEO_BUDGET_MS = 12e4;
541
+ function flagsLine(g) {
542
+ const parts = [
543
+ g.is_favorite ? "\u2B50 like" : null,
544
+ g.is_approved_plan ? "\u2714\uFE0F aprovado" : null
545
+ ].filter(Boolean);
546
+ return parts.length ? `
547
+ ${parts.join(" \xB7 ")}` : "";
548
+ }
549
+ function firstOutputUrl(output) {
550
+ if (!output) return null;
551
+ const o = output;
552
+ if (Array.isArray(o) && typeof o[0] === "string") return o[0];
553
+ if (Array.isArray(o.urls) && typeof o.urls[0] === "string") return o.urls[0];
554
+ if (typeof o.url === "string") return o.url;
555
+ return null;
556
+ }
500
557
  function registerGenerationTools(server, client, cfg) {
501
558
  server.registerTool(
502
559
  "generate_image",
@@ -777,7 +834,7 @@ ${footer}`);
777
834
  const blocks = await buildImageBlocks(urls, cfg);
778
835
  const list = urls.map((u, i) => `${i + 1}. ${u}`).join("\n") || "(sem URLs)";
779
836
  return { content: [{ type: "text", text: `\u2705 Pronto.
780
- ${list}` }, ...blocks] };
837
+ ${list}${flagsLine(status)}` }, ...blocks] };
781
838
  }
782
839
  if (status.status === "failed") {
783
840
  return errorResult(`Gera\xE7\xE3o falhou: ${status.error_message || "erro desconhecido"}.`);
@@ -790,6 +847,43 @@ ${list}` }, ...blocks] };
790
847
  }
791
848
  }
792
849
  );
850
+ server.registerTool(
851
+ "list_generations",
852
+ {
853
+ title: "Listar gera\xE7\xF5es",
854
+ description: 'Lista as suas gera\xE7\xF5es (imagens/v\xEDdeos) mais recentes, com os flags de favorito ("like") e de plano aprovado. Use os filtros favorite=true / approved=true para ver s\xF3 as favoritadas ou s\xF3 as aprovadas. Retorna id, modelo, tipo, status, data, um trecho do prompt e (quando h\xE1) a URL.',
855
+ inputSchema: {
856
+ limit: z.number().int().min(1).max(100).optional().describe("Quantas trazer (padr\xE3o 20, m\xE1x 100)."),
857
+ offset: z.number().int().min(0).optional().describe("Deslocamento para paginar (padr\xE3o 0)."),
858
+ favorite: z.boolean().optional().describe('S\xF3 as favoritadas ("like"). Padr\xE3o: todas.'),
859
+ approved: z.boolean().optional().describe("S\xF3 as com plano aprovado. Padr\xE3o: todas.")
860
+ }
861
+ },
862
+ async ({ limit, offset, favorite, approved }) => {
863
+ try {
864
+ const { generations } = await client.listGenerations({ limit, offset, favorite, approved });
865
+ if (!generations.length) {
866
+ const scope = favorite && approved ? " (favoritadas + aprovadas)" : favorite ? " favoritadas" : approved ? " aprovadas" : "";
867
+ return textResult(`Nenhuma gera\xE7\xE3o${scope} encontrada.`);
868
+ }
869
+ const lines = generations.map((g, i) => {
870
+ const type = g.generation_type || "image";
871
+ const when = g.created_at ? new Date(g.created_at).toISOString().slice(0, 10) : "\u2014";
872
+ const prompt = (g.prompt || "").replace(/\s+/g, " ").slice(0, 80);
873
+ const url = firstOutputUrl(g.output);
874
+ const marks = [g.is_favorite ? "\u2B50" : null, g.is_approved_plan ? "\u2714\uFE0F" : null].filter(Boolean).join(" ");
875
+ const marksSuffix = marks ? ` ${marks}` : "";
876
+ return `${i + 1}. ${type} \xB7 ${g.status} \xB7 ${when} \xB7 ${g.model}${marksSuffix}
877
+ ${g.id}
878
+ "${prompt}"${url ? `
879
+ ${url}` : ""}`;
880
+ });
881
+ return textResult(lines.join("\n\n"));
882
+ } catch (e) {
883
+ return errorResult(apiErrorToUserMessage(e));
884
+ }
885
+ }
886
+ );
793
887
  server.registerTool(
794
888
  "cancel_generation",
795
889
  {
@@ -895,10 +989,12 @@ function registerAudioTools(server, client, cfg) {
895
989
  if (res.diamonds_refunded) parts.push(`Estorno: ${res.diamonds_refunded} \u{1F48E}`);
896
990
  const projLine = res.project_code ? `
897
991
  \u{1F4C1} Projeto: ${res.project_code}${res.project_name ? ` \u2014 ${res.project_name}` : ""}` : "";
992
+ const wa = weeklyAllowanceLine(res.weekly_allowance);
898
993
  return textResult(
899
994
  `\u2705 \xC1udio gerado (${res.model}, voz ${res.voice}, ${res.duration_sec.toFixed(1)}s).
900
995
  ${res.url}
901
- ${parts.join(" \xB7 ")}${projLine}`
996
+ ${parts.join(" \xB7 ")}${projLine}` + (wa ? `
997
+ ${wa}` : "")
902
998
  );
903
999
  } catch (e) {
904
1000
  const msg = e instanceof ApiError ? e.message : e instanceof Error ? e.message : "";
@@ -1005,9 +1101,11 @@ function registerAccountTools(server, client, _cfg) {
1005
1101
  async () => {
1006
1102
  try {
1007
1103
  const me = await client.me();
1104
+ const wa = weeklyAllowanceLine(me.weekly_allowance);
1008
1105
  return textResult(
1009
1106
  `\u{1F464} ${me.name ?? "(sem nome)"} <${me.email ?? "sem email"}>
1010
- Saldo: ${me.diamonds} \u{1F48E} \xB7 auth: ${me.authType}`
1107
+ Saldo: ${me.diamonds} \u{1F48E} \xB7 auth: ${me.authType}` + (wa ? `
1108
+ ${wa}` : "")
1011
1109
  );
1012
1110
  } catch (e) {
1013
1111
  return errorResult(apiErrorToUserMessage(e));
@@ -1018,13 +1116,15 @@ Saldo: ${me.diamonds} \u{1F48E} \xB7 auth: ${me.authType}`
1018
1116
  "get_balance",
1019
1117
  {
1020
1118
  title: "Saldo de diamantes",
1021
- description: "Mostra o saldo atual de diamantes da conta vinculada.",
1119
+ description: "Mostra o saldo atual de diamantes e, para membros da equipe, o cr\xE9dito semanal (% usado, quanto resta e quando reseta).",
1022
1120
  inputSchema: {}
1023
1121
  },
1024
1122
  async () => {
1025
1123
  try {
1026
1124
  const b = await client.balance();
1027
- return textResult(`Saldo: ${b.diamonds} \u{1F48E}`);
1125
+ const wa = weeklyAllowanceLine(b.weekly_allowance);
1126
+ return textResult(`Saldo: ${b.diamonds} \u{1F48E}` + (wa ? `
1127
+ ${wa}` : ""));
1028
1128
  } catch (e) {
1029
1129
  return errorResult(apiErrorToUserMessage(e));
1030
1130
  }
@@ -1312,12 +1412,13 @@ function fmtDate(iso) {
1312
1412
  return iso ? iso.slice(0, 10) : "";
1313
1413
  }
1314
1414
  function callLine(c) {
1415
+ const company = c.company_name ? ` \xB7 ${c.company_name}` : "";
1315
1416
  const proj = c.project_name ? ` \xB7 ${c.client_name ? c.client_name + " / " : ""}${c.project_name}` : "";
1316
1417
  const who = c.speakers.length ? ` \xB7 ${c.speakers.join(", ")}` : c.participant_count ? ` \xB7 ${c.participant_count} falantes` : "";
1317
1418
  const vis = VIS_LABEL[c.visibility] ?? c.visibility;
1318
1419
  const flag = c.status !== "ready" ? ` [${c.status}]` : "";
1319
1420
  return `\u2022 ${c.title ?? "(sem t\xEDtulo)"}${flag}
1320
- ${fmtDate(c.date)} \xB7 ${fmtDuration(c.duration_sec)} \xB7 ${vis}${proj}${who}
1421
+ ${fmtDate(c.date)} \xB7 ${fmtDuration(c.duration_sec)} \xB7 ${vis}${company}${proj}${who}
1321
1422
  id: ${c.id}`;
1322
1423
  }
1323
1424
  function renderCall(c) {
@@ -1327,6 +1428,7 @@ function renderCall(c) {
1327
1428
  if (c.date) meta.push(fmtDate(c.date));
1328
1429
  meta.push(fmtDuration(c.duration_sec));
1329
1430
  meta.push(VIS_LABEL[c.visibility] ?? c.visibility);
1431
+ if (c.company_name) meta.push(c.company_name);
1330
1432
  if (c.project_name) meta.push(`${c.client_name ? c.client_name + " / " : ""}${c.project_name}`);
1331
1433
  if (c.status !== "ready") meta.push(`status: ${c.status}`);
1332
1434
  lines.push(meta.join(" \xB7 "));
@@ -1357,13 +1459,15 @@ function registerCallTools(server, client, _cfg) {
1357
1459
  "search_calls",
1358
1460
  {
1359
1461
  title: "Buscar calls",
1360
- description: "Busca nas calls (reuni\xF5es gravadas e transcritas) vis\xEDveis pra conta \u2014 suas, da equipe e compartilhadas. Todos os filtros s\xE3o opcionais e combin\xE1veis: `query` (texto no t\xEDtulo/projeto/cliente/falante), `project` (code/uuid/nome), `client` (code/nome), `visibility` (team|private|workspace|link), `speaker` (nome do falante). Retorna uma lista resumida \u2014 use get_call com o id pra ler a transcri\xE7\xE3o completa.",
1462
+ description: 'Busca nas calls (reuni\xF5es gravadas e transcritas) vis\xEDveis pra conta \u2014 suas, da equipe e compartilhadas. Todos os filtros s\xE3o opcionais e combin\xE1veis: `query` (texto no t\xEDtulo/projeto/cliente/falante), `project` (code/uuid/nome), `client` (code/nome), `company` (empresa/equipe do dono, ex.: "BePlus"), `visibility` (team|private|workspace|link), `speaker` (nome do falante), `mine` (s\xF3 as que EU gravei). Retorna uma lista resumida \u2014 use get_call com o id pra ler a transcri\xE7\xE3o completa.',
1361
1463
  inputSchema: {
1362
1464
  query: z8.string().max(200).optional().describe("Texto livre \u2014 casa t\xEDtulo, projeto, cliente ou falante."),
1363
1465
  project: z8.string().max(64).optional().describe('Projeto: code (ex.: "CONTEUDO-INS"), uuid ou parte do nome.'),
1364
1466
  client: z8.string().max(128).optional().describe("Cliente: code ou parte do nome."),
1467
+ company: z8.string().max(128).optional().describe('Empresa/equipe do dono da call (ex.: "BePlus"). Filtra por parte do nome.'),
1365
1468
  visibility: z8.enum(["team", "private", "workspace", "link"]).optional().describe("Privacidade: team (equipe), private (privada), workspace (projeto) ou link."),
1366
1469
  speaker: z8.string().max(128).optional().describe("Nome do falante."),
1470
+ mine: z8.boolean().optional().describe('true = s\xF3 as calls que EU gravei (sou o dono). Use pra "minhas grava\xE7\xF5es".'),
1367
1471
  limit: z8.number().int().min(1).max(50).optional().describe("M\xE1ximo de resultados (padr\xE3o 20).")
1368
1472
  }
1369
1473
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beplus-mcp",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Conector MCP da equipe BePlus — gere imagens/vídeos/áudio e consulte calls, projetos e clientes pela sua conta BePlus (diamantes, limites e histórico aplicados pela plataforma).",
5
5
  "type": "module",
6
6
  "bin": {