@astramindapp/mcp-server 0.14.0 → 0.17.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/server.js CHANGED
@@ -26,7 +26,7 @@
26
26
  * mind_sense — MINDsense emotional intelligence layer
27
27
  * mind_research — Deep research agent jobs
28
28
  * mind_train — Self-training and chat-to-KG sessions
29
- * mind_social — Thoughts, communities, and feed
29
+ * mind_social — Public feed posts, communities, and social feed
30
30
  * mind_profile — Profile, prompts, and model preferences
31
31
  * mind_insights — ALE insights and analytics
32
32
  * mind_automate — Automations and triggers
@@ -48,7 +48,7 @@ const integration_guide_js_1 = require("./integration-guide.js");
48
48
  function createMindMcpServer(client) {
49
49
  const server = new mcp_js_1.McpServer({
50
50
  name: "mind",
51
- version: "0.10.0",
51
+ version: "0.17.0",
52
52
  }, {
53
53
  // Returned to every client in the MCP `initialize` response — the first
54
54
  // thing any connecting agent sees about how to integrate with MIND.
@@ -72,7 +72,7 @@ function createMindMcpServer(client) {
72
72
  // ─── mind_query ─────────────────────────────────────────
73
73
  // Semantic search across the user's knowledge graph.
74
74
  // Replaces flat MEMORY.md — returns only relevant memories.
75
- server.tool("mind_query", "Search your MIND knowledge graph. Returns AI-synthesized answer from your stored documents, entries, and thoughts. Use this BEFORE making decisions — MIND is your memory.", {
75
+ server.tool("mind_query", "Search your MIND knowledge graph. Returns AI-synthesized answer from your stored documents, entries, and feed posts. Use this BEFORE making decisions — MIND is your memory.", {
76
76
  query: zod_1.z.string().describe("What to search for in your knowledge graph"),
77
77
  mode: zod_1.z
78
78
  .enum(["mix", "hybrid", "global", "local", "naive"])
@@ -105,7 +105,7 @@ function createMindMcpServer(client) {
105
105
  // ─── mind_remember ──────────────────────────────────────
106
106
  // Store/manage content in the knowledge graph. Auto-categorized by type.
107
107
  // Enhanced: now supports create, delete, search, get, list actions.
108
- server.tool("mind_remember", "Store and manage content in your MIND knowledge graph. Use for facts, decisions, learnings, research, notes — anything worth remembering. Auto-categorized. Always log outcomes here after completing tasks. Supports create (default), delete, search, get, and list.", {
108
+ server.tool("mind_remember", "Store and manage content in your MIND knowledge graph. Use for facts, decisions, learnings, research, notes — anything worth remembering. Auto-categorized. Always log outcomes here after completing tasks. Supports create (default), delete, search, get, and list.\n\n⚠️ PRIVATE vs PUBLIC: `document` and `entry` are PRIVATE to the user's knowledge graph. `feed_post` is a PUBLIC social-media post that appears on the user's public feed for everyone to see. Default to `entry` for all agent outcomes, logs, decisions, and research. NEVER use `feed_post` unless the user explicitly says \"post\", \"share\", \"tweet\", \"feed\", or \"thought to my feed\" — deploy logs, PR notes, work outcomes, and agent activity belong in `entry`, NOT on the public feed.", {
109
109
  action: zod_1.z
110
110
  .enum(["create", "delete", "search", "get", "list"])
111
111
  .optional()
@@ -113,14 +113,14 @@ function createMindMcpServer(client) {
113
113
  .describe("Action: create (store new content — default), delete (remove by ID), search (find entries), get (retrieve by ID), list (paginated listing)"),
114
114
  content: zod_1.z.string().optional().describe("What to remember — the actual content to store (required for create)"),
115
115
  type: zod_1.z
116
- .enum(["document", "entry", "thought"])
116
+ .enum(["document", "entry", "feed_post", "thought"])
117
117
  .optional()
118
118
  .default("entry")
119
- .describe("Storage type: document (long-form, structured — research, specs, strategies), entry (medium — observations, findings, action logs), thought (quick — fleeting ideas, one-liners)"),
119
+ .describe("Storage type. PRIVATE: `document` (long-form, structured — research, specs, strategies), `entry` (medium — observations, findings, action logs, agent outcomes — DEFAULT for agent work). PUBLIC: `feed_post` (a social-media-style post that appears on the user's PUBLIC feed for everyone to see — NEVER use unless the user explicitly said \"post\", \"share\", \"tweet\", \"feed\", or \"thought to my feed\"). `thought` is a deprecated alias for `feed_post` and behaves identically — prefer `feed_post` for clarity."),
120
120
  title: zod_1.z
121
121
  .string()
122
122
  .optional()
123
- .describe("Title for documents and entries (auto-generated if omitted for thoughts)"),
123
+ .describe("Title for documents and entries (auto-generated if omitted for feed posts)"),
124
124
  tags: zod_1.z
125
125
  .array(zod_1.z.string())
126
126
  .optional()
@@ -167,9 +167,10 @@ function createMindMcpServer(client) {
167
167
  });
168
168
  storedAs = "document";
169
169
  break;
170
+ case "feed_post":
170
171
  case "thought":
171
172
  result = await client.createThought({ content });
172
- storedAs = "thought";
173
+ storedAs = "feed_post";
173
174
  break;
174
175
  case "entry":
175
176
  default:
@@ -202,6 +203,7 @@ function createMindMcpServer(client) {
202
203
  case "document":
203
204
  await client.deleteDocument(item_id);
204
205
  break;
206
+ case "feed_post":
205
207
  case "thought":
206
208
  await client.deleteThought(item_id);
207
209
  break;
@@ -211,7 +213,7 @@ function createMindMcpServer(client) {
211
213
  break;
212
214
  }
213
215
  return {
214
- content: [{ type: "text", text: `✅ Deleted ${type} ${item_id}` }],
216
+ content: [{ type: "text", text: `✅ Deleted ${type === "thought" ? "feed_post" : type} ${item_id}` }],
215
217
  };
216
218
  }
217
219
  case "search": {
@@ -257,11 +259,12 @@ function createMindMcpServer(client) {
257
259
  const lines = docs.map((d) => `• ${d.title} (status: ${d.status}, source: ${d.source}) — id: ${d.id}`);
258
260
  return { content: [{ type: "text", text: lines.join("\n") }] };
259
261
  }
262
+ case "feed_post":
260
263
  case "thought": {
261
264
  const result = await client.listThoughts();
262
265
  const thoughts = result.thoughts ?? [];
263
266
  if (thoughts.length === 0) {
264
- return { content: [{ type: "text", text: "No thoughts found." }] };
267
+ return { content: [{ type: "text", text: "No feed posts found." }] };
265
268
  }
266
269
  const lines = thoughts.map((t) => `• ${t.content?.slice(0, 100)}... — id: ${t.id ?? t.thought_id}`);
267
270
  return { content: [{ type: "text", text: lines.join("\n") }] };
@@ -1808,7 +1811,7 @@ function createMindMcpServer(client) {
1808
1811
  });
1809
1812
  // ─── mind_social ────────────────────────────────────────
1810
1813
  // Thoughts, communities, and feed.
1811
- server.tool("mind_social", "Interact with MIND's social layer — create thoughts (posts), browse the feed, manage communities, and engage with other users' content.", {
1814
+ server.tool("mind_social", "Interact with MIND's social layer — create thoughts (PUBLIC feed posts), browse the feed, manage communities, and engage with other users' content. ⚠️ create_thought posts to the user's PUBLIC social feed for everyone to see — NEVER call unless the user explicitly said \"post\", \"share\", \"tweet\", \"feed\", or \"thought to my feed\". For private agent outcomes, deploy logs, or work updates, use mind_remember with type=entry instead.", {
1812
1815
  action: zod_1.z
1813
1816
  .enum([
1814
1817
  "create_thought", "get_thought", "delete_thought", "like_thought",
@@ -1842,7 +1845,7 @@ function createMindMcpServer(client) {
1842
1845
  content: [
1843
1846
  {
1844
1847
  type: "text",
1845
- text: `✅ Thought posted (id: ${result.thought_id ?? result.id})`,
1848
+ text: `✅ Feed post created on PUBLIC feed (id: ${result.thought_id ?? result.id})`,
1846
1849
  },
1847
1850
  ],
1848
1851
  };
@@ -3524,6 +3527,527 @@ function createMindMcpServer(client) {
3524
3527
  };
3525
3528
  }
3526
3529
  });
3530
+ // ─── mind_social ────────────────────────────────────────
3531
+ // Read-only analytics across YouTube, LinkedIn, X, Twitch + goals progress.
3532
+ server.tool("mind_social", "Read social media analytics from MIND's Social Dashboard — YouTube/LinkedIn/X/Twitch channel stats, recent videos with performance, retention curves, traffic sources, comment sentiment, and goal progress. Use this to answer questions like 'how did Tuesday's video do?' or 'am I on pace for 1k subs?'", {
3533
+ action: zod_1.z
3534
+ .enum([
3535
+ "status",
3536
+ "summary",
3537
+ "yt_channel",
3538
+ "yt_videos",
3539
+ "yt_video_detail",
3540
+ "goals",
3541
+ ])
3542
+ .describe("Which read to perform: status (per-platform connection state), summary (cross-platform KPIs), yt_channel (channel snapshot + 28-day history), yt_videos (recent videos with perf), yt_video_detail (one video + retention + traffic + sentiment), goals (goal progress)."),
3543
+ video_id: zod_1.z
3544
+ .string()
3545
+ .optional()
3546
+ .describe("Required for yt_video_detail."),
3547
+ limit: zod_1.z
3548
+ .number()
3549
+ .int()
3550
+ .optional()
3551
+ .describe("Max items for yt_videos (default 25)."),
3552
+ }, async ({ action, video_id, limit }) => {
3553
+ try {
3554
+ switch (action) {
3555
+ case "status": {
3556
+ const r = (await client.socialStatus());
3557
+ const lines = ["**Social Dashboard status**"];
3558
+ lines.push(`Enabled: ${r.enabled ? "yes" : "no"} (global flag: ${r.globally_enabled ? "on" : "off"})`);
3559
+ const platforms = r.platforms || {};
3560
+ for (const key of ["youtube", "linkedin", "x", "twitch"]) {
3561
+ const p = platforms[key] || {};
3562
+ lines.push(`• ${key}: ${p.connected ? `connected (${p.account_label || "—"})` : p.configured ? "not connected" : "not configured"}`);
3563
+ }
3564
+ return {
3565
+ content: [{ type: "text", text: lines.join("\n") }],
3566
+ };
3567
+ }
3568
+ case "summary": {
3569
+ const r = (await client.socialSummary());
3570
+ const yt = r.youtube || {};
3571
+ const lines = [
3572
+ "**Cross-platform summary**",
3573
+ `YouTube subs: ${yt.subs ?? "—"}${yt.subs_delta_28d_pct != null ? ` (28d Δ ${yt.subs_delta_28d_pct}%)` : ""}`,
3574
+ `YouTube views: ${yt.total_views ?? "—"}${yt.views_delta_28d_pct != null ? ` (28d Δ ${yt.views_delta_28d_pct}%)` : ""}`,
3575
+ `YouTube watch minutes (28d): ${yt.watch_minutes_28d ?? "—"}`,
3576
+ `LinkedIn posts recent: ${(r.linkedin || {}).post_count_recent ?? "—"}`,
3577
+ `X tweets recent: ${(r.x || {}).tweet_count_recent ?? "—"}`,
3578
+ `Twitch VODs recent: ${(r.twitch || {}).vod_count_recent ?? "—"}`,
3579
+ ];
3580
+ const goals = r.goals || [];
3581
+ if (goals.length) {
3582
+ lines.push("\n**Goals**");
3583
+ for (const g of goals) {
3584
+ lines.push(`• ${g.label || g.metric}: ${g.current ?? 0}/${g.target} (${g.pct ?? 0}%) — ${g.status}`);
3585
+ }
3586
+ }
3587
+ return {
3588
+ content: [{ type: "text", text: lines.join("\n") }],
3589
+ };
3590
+ }
3591
+ case "yt_channel": {
3592
+ const r = (await client.socialYouTubeChannel());
3593
+ const latest = r.latest || {};
3594
+ const history = r.history || [];
3595
+ const lines = [
3596
+ "**YouTube channel**",
3597
+ `Subs: ${latest.subs ?? "—"}`,
3598
+ `Total views: ${latest.total_views ?? "—"}`,
3599
+ `Total watch minutes (28d): ${latest.total_watch_time_minutes ?? "—"}`,
3600
+ `Videos published: ${latest.video_count ?? "—"}`,
3601
+ `History points (last ${history.length} days):`,
3602
+ ...history.slice(-7).map((h) => ` ${h.date}: ${h.subs} subs, ${h.total_views} views`),
3603
+ ];
3604
+ return {
3605
+ content: [{ type: "text", text: lines.join("\n") }],
3606
+ };
3607
+ }
3608
+ case "yt_videos": {
3609
+ const r = (await client.socialYouTubeVideos(limit ?? 25));
3610
+ const items = r.items || [];
3611
+ if (!items.length) {
3612
+ return {
3613
+ content: [{ type: "text", text: "No videos in snapshot cache yet." }],
3614
+ };
3615
+ }
3616
+ const lines = [`**Recent videos** (${items.length})`];
3617
+ for (const v of items.slice(0, 15)) {
3618
+ const l = v.latest || {};
3619
+ lines.push(`• ${v.title} — ${l.views ?? "—"} views, ${l.ctr_percent != null ? l.ctr_percent.toFixed(1) + "%" : "—"} CTR, ${l.comments ?? "—"} comments [${v.video_id}]`);
3620
+ }
3621
+ return {
3622
+ content: [{ type: "text", text: lines.join("\n") }],
3623
+ };
3624
+ }
3625
+ case "yt_video_detail": {
3626
+ if (!video_id) {
3627
+ return {
3628
+ content: [
3629
+ { type: "text", text: "Error: video_id is required for yt_video_detail" },
3630
+ ],
3631
+ isError: true,
3632
+ };
3633
+ }
3634
+ const r = (await client.socialYouTubeVideoDetail(video_id));
3635
+ const meta = r.metadata || {};
3636
+ const latest = r.latest || {};
3637
+ const traffic = r.traffic || [];
3638
+ const sent = r.comments?.sentiment_summary || {};
3639
+ const lines = [
3640
+ `**${meta.title}**`,
3641
+ `Published: ${meta.published_at} · ${meta.duration_seconds ? Math.round(meta.duration_seconds / 60) + " min" : "—"}`,
3642
+ `Views: ${latest.views ?? "—"} · CTR: ${latest.ctr_percent != null ? latest.ctr_percent.toFixed(1) + "%" : "—"} · AVD: ${latest.avd_seconds ? Math.round(latest.avd_seconds) + "s" : "—"}`,
3643
+ `Subs Δ: +${latest.subscribers_gained ?? 0} / -${latest.subscribers_lost ?? 0}`,
3644
+ "",
3645
+ "Traffic sources:",
3646
+ ...traffic.slice(0, 5).map((t) => ` • ${t.source}: ${t.views}`),
3647
+ "",
3648
+ `Comments: ${sent.count ?? 0} (${sent.positive ?? 0} pos / ${sent.neutral ?? 0} neu / ${sent.negative ?? 0} neg, avg ${(sent.avg_score ?? 0).toFixed(2)})`,
3649
+ ];
3650
+ return {
3651
+ content: [{ type: "text", text: lines.join("\n") }],
3652
+ };
3653
+ }
3654
+ case "goals": {
3655
+ const r = (await client.socialGoals());
3656
+ const items = r.items || [];
3657
+ if (!items.length) {
3658
+ return {
3659
+ content: [{ type: "text", text: "No goals set." }],
3660
+ };
3661
+ }
3662
+ const lines = ["**Goals**"];
3663
+ for (const g of items) {
3664
+ lines.push(`• ${g.label || g.metric}: ${g.current ?? 0}/${g.target} (${g.pct ?? 0}%) — due ${g.due_date} — ${g.status}`);
3665
+ }
3666
+ return {
3667
+ content: [{ type: "text", text: lines.join("\n") }],
3668
+ };
3669
+ }
3670
+ }
3671
+ }
3672
+ catch (err) {
3673
+ return {
3674
+ content: [{ type: "text", text: `mind_social error: ${err}` }],
3675
+ isError: true,
3676
+ };
3677
+ }
3678
+ });
3679
+ // ─── mind_personas ──────────────────────────────────────────
3680
+ // Influencer Factory Command Center surface. Admin-only.
3681
+ // Whole router is dark unless IF_FEATURE_FLAG_ENABLED=true on the server.
3682
+ // Persona == featured_minds row (1:1) — IF fields stored on featured_minds,
3683
+ // asset library (face/voice/bios/Blotato) on the persona_assets collection.
3684
+ server.tool("mind_personas", "Influencer Factory Command Center — synthetic-persona creators that publish across Blotato platforms. Admin-only. Phase 1 surface: persona CRUD (auto-creates a Featured MIND row with IF fields), face anchor (AI-generate via Nano Banana Pro OR user-uploaded with rights affirmation), face variants (image-to-image via n8n + Fal.ai, always pinned to anchor — never chained), voice (ElevenLabs library search + clone + sample), per-platform bios (with optional LLM draft), Blotato account registration (YouTube/IG/LinkedIn/X/Threads/Pinterest; TikTok marked manual_upload). Each persona is publicly chattable at /m/{username} via its linked Featured MIND.", {
3685
+ action: zod_1.z
3686
+ .enum([
3687
+ "health",
3688
+ "list_personas",
3689
+ "get_persona",
3690
+ "create_persona",
3691
+ "update_persona",
3692
+ "delete_persona",
3693
+ "anchor_face_ai_generate",
3694
+ "request_face_variants",
3695
+ "list_face_variants",
3696
+ "search_voice_library",
3697
+ "set_voice_library",
3698
+ "generate_voice_sample",
3699
+ "update_bios",
3700
+ "blotato_whoami",
3701
+ "blotato_accounts",
3702
+ "register_blotato_account",
3703
+ "unregister_blotato_account",
3704
+ ])
3705
+ .describe("What to do. Start with 'health' to confirm Fal/ElevenLabs/Blotato/S3/n8n are configured. Most write actions require persona_mind_id."),
3706
+ persona_mind_id: zod_1.z
3707
+ .string()
3708
+ .optional()
3709
+ .describe("Persona id (== featured_minds.mind_id). Required for every per-persona action."),
3710
+ // create_persona
3711
+ username: zod_1.z
3712
+ .string()
3713
+ .optional()
3714
+ .describe("Lowercase username (3–32 chars, [a-z0-9_-]). Used for /m/{username} public landing AND the featured_minds row. Required for create_persona."),
3715
+ display_name: zod_1.z.string().optional().describe("Display name. Required for create_persona."),
3716
+ niche: zod_1.z.string().optional().describe("Niche label, e.g. 'fitness', 'wealth'."),
3717
+ pillars: zod_1.z
3718
+ .array(zod_1.z.string())
3719
+ .optional()
3720
+ .describe("3–5 content pillars the persona writes about."),
3721
+ tone: zod_1.z
3722
+ .string()
3723
+ .optional()
3724
+ .describe("Tone descriptor, e.g. 'warm-direct', 'contrarian-analytical'."),
3725
+ archetype_id: zod_1.z
3726
+ .string()
3727
+ .optional()
3728
+ .describe("Persona archetype template id (looked up in persona_archetypes catalog)."),
3729
+ kg_scope_template_id: zod_1.z
3730
+ .string()
3731
+ .optional()
3732
+ .describe("Knowledge-graph scope template id (bounds what this persona 'knows about')."),
3733
+ niche_tags: zod_1.z
3734
+ .array(zod_1.z.string())
3735
+ .optional()
3736
+ .describe("Topic niche tags used by retrieval (separate from Featured MIND catalog tags)."),
3737
+ daily_credit_ceiling_usd: zod_1.z
3738
+ .number()
3739
+ .optional()
3740
+ .describe("Hard ceiling on daily Fal.ai/ElevenLabs/Veo/Suno spend for this persona. Default 5."),
3741
+ // update_persona — partial
3742
+ status: zod_1.z
3743
+ .enum(["draft", "active", "paused"])
3744
+ .optional()
3745
+ .describe("Persona runtime status."),
3746
+ agent_posting_enabled: zod_1.z
3747
+ .boolean()
3748
+ .optional()
3749
+ .describe("Master kill-switch on the linked Featured MIND row. Off = autonomous posters skip this persona."),
3750
+ // anchor_face_ai_generate
3751
+ prompt: zod_1.z
3752
+ .string()
3753
+ .optional()
3754
+ .describe("Anchor-face generation prompt OR voice sample text (anchor_face_ai_generate, generate_voice_sample)."),
3755
+ model: zod_1.z
3756
+ .enum(["nano_banana_pro", "flux"])
3757
+ .optional()
3758
+ .describe("Anchor-face generator model. Default nano_banana_pro."),
3759
+ // request_face_variants
3760
+ count: zod_1.z
3761
+ .number()
3762
+ .optional()
3763
+ .describe("Variant count (1–20). Default 5."),
3764
+ prompt_modifier: zod_1.z
3765
+ .string()
3766
+ .optional()
3767
+ .describe("Optional modifier appended to the base variant prompt (e.g. 'outdoor golden hour')."),
3768
+ // voice
3769
+ voice_query: zod_1.z
3770
+ .string()
3771
+ .optional()
3772
+ .describe("ElevenLabs library search query (search_voice_library)."),
3773
+ voice_id: zod_1.z
3774
+ .string()
3775
+ .optional()
3776
+ .describe("ElevenLabs voice id (set_voice_library)."),
3777
+ voice_name: zod_1.z
3778
+ .string()
3779
+ .optional()
3780
+ .describe("Display name to store for the voice (set_voice_library)."),
3781
+ voice_text: zod_1.z
3782
+ .string()
3783
+ .optional()
3784
+ .describe("Text to render as a sample MP3 (generate_voice_sample)."),
3785
+ // bios
3786
+ bios: zod_1.z
3787
+ .record(zod_1.z.string(), zod_1.z.string())
3788
+ .optional()
3789
+ .describe("Map of platform → bio text (twitter|instagram|tiktok|linkedin|youtube|threads|pinterest). Length-capped server-side."),
3790
+ generate_with_llm: zod_1.z
3791
+ .boolean()
3792
+ .optional()
3793
+ .describe("If true, LLM drafts missing platform bios. Existing bios stay."),
3794
+ // blotato
3795
+ platform: zod_1.z
3796
+ .enum([
3797
+ "twitter",
3798
+ "instagram",
3799
+ "tiktok",
3800
+ "linkedin",
3801
+ "youtube",
3802
+ "threads",
3803
+ "pinterest",
3804
+ ])
3805
+ .optional()
3806
+ .describe("Target platform for Blotato register/unregister."),
3807
+ account_id: zod_1.z
3808
+ .string()
3809
+ .optional()
3810
+ .describe("Blotato account id (from blotato_accounts list)."),
3811
+ page_id: zod_1.z
3812
+ .string()
3813
+ .optional()
3814
+ .describe("LinkedIn / IG / YouTube page id (optional, platform-specific)."),
3815
+ board_id: zod_1.z
3816
+ .string()
3817
+ .optional()
3818
+ .describe("Pinterest board id (REQUIRED for Pinterest)."),
3819
+ handle: zod_1.z.string().optional().describe("Display handle (optional)."),
3820
+ media_type: zod_1.z
3821
+ .enum(["story", "reel"])
3822
+ .optional()
3823
+ .describe("Instagram media type (story or reel)."),
3824
+ // list filters
3825
+ search: zod_1.z.string().optional().describe("Search filter for list_personas."),
3826
+ }, async (args) => {
3827
+ try {
3828
+ const { action, persona_mind_id: pid, username, display_name, niche, pillars, tone, archetype_id, kg_scope_template_id, niche_tags, daily_credit_ceiling_usd, status, agent_posting_enabled, prompt, model, count, prompt_modifier, voice_query, voice_id, voice_name, voice_text, bios, generate_with_llm, platform, account_id, page_id, board_id, handle, media_type, search, } = args;
3829
+ const needPid = () => {
3830
+ if (!pid)
3831
+ throw new Error(`${action} requires persona_mind_id`);
3832
+ };
3833
+ switch (action) {
3834
+ case "health": {
3835
+ const r = await client.ifHealth();
3836
+ return {
3837
+ content: [
3838
+ { type: "text", text: JSON.stringify(r, null, 2) },
3839
+ ],
3840
+ };
3841
+ }
3842
+ case "list_personas": {
3843
+ const r = await client.ifListPersonas({ status, search });
3844
+ if (!r.length) {
3845
+ return { content: [{ type: "text", text: "No personas." }] };
3846
+ }
3847
+ const lines = r.map((p) => `• @${p.username} — ${p.display_name} [${p.status}] (${p.persona_mind_id})`);
3848
+ return { content: [{ type: "text", text: lines.join("\n") }] };
3849
+ }
3850
+ case "get_persona": {
3851
+ needPid();
3852
+ const r = await client.ifGetPersonaFull(pid);
3853
+ return {
3854
+ content: [
3855
+ { type: "text", text: JSON.stringify(r, null, 2) },
3856
+ ],
3857
+ };
3858
+ }
3859
+ case "create_persona": {
3860
+ if (!username || !display_name)
3861
+ throw new Error("username and display_name are required");
3862
+ const r = await client.ifCreatePersona({
3863
+ username,
3864
+ display_name,
3865
+ niche,
3866
+ pillars,
3867
+ tone,
3868
+ archetype_id,
3869
+ kg_scope_template_id,
3870
+ niche_tags,
3871
+ daily_credit_ceiling_usd,
3872
+ });
3873
+ return {
3874
+ content: [
3875
+ {
3876
+ type: "text",
3877
+ text: `Created persona @${r.username} (mind_id=${r.persona_mind_id})`,
3878
+ },
3879
+ ],
3880
+ };
3881
+ }
3882
+ case "update_persona": {
3883
+ needPid();
3884
+ const patch = {};
3885
+ if (display_name !== undefined)
3886
+ patch.display_name = display_name;
3887
+ if (niche !== undefined)
3888
+ patch.niche = niche;
3889
+ if (pillars !== undefined)
3890
+ patch.pillars = pillars;
3891
+ if (tone !== undefined)
3892
+ patch.tone = tone;
3893
+ if (daily_credit_ceiling_usd !== undefined)
3894
+ patch.daily_credit_ceiling_usd = daily_credit_ceiling_usd;
3895
+ if (status !== undefined)
3896
+ patch.status = status;
3897
+ if (archetype_id !== undefined)
3898
+ patch.archetype_id = archetype_id;
3899
+ if (kg_scope_template_id !== undefined)
3900
+ patch.kg_scope_template_id = kg_scope_template_id;
3901
+ if (niche_tags !== undefined)
3902
+ patch.niche_tags = niche_tags;
3903
+ if (agent_posting_enabled !== undefined)
3904
+ patch.agent_posting_enabled = agent_posting_enabled;
3905
+ const r = await client.ifUpdatePersona(pid, patch);
3906
+ return {
3907
+ content: [{ type: "text", text: JSON.stringify(r, null, 2) }],
3908
+ };
3909
+ }
3910
+ case "delete_persona": {
3911
+ needPid();
3912
+ const r = await client.ifDeletePersona(pid);
3913
+ return {
3914
+ content: [
3915
+ { type: "text", text: JSON.stringify(r, null, 2) },
3916
+ ],
3917
+ };
3918
+ }
3919
+ case "anchor_face_ai_generate": {
3920
+ needPid();
3921
+ if (!prompt)
3922
+ throw new Error("prompt is required");
3923
+ const r = await client.ifAnchorAIGenerate(pid, { prompt, model });
3924
+ return {
3925
+ content: [
3926
+ { type: "text", text: JSON.stringify(r, null, 2) },
3927
+ ],
3928
+ };
3929
+ }
3930
+ case "request_face_variants": {
3931
+ needPid();
3932
+ const r = await client.ifRequestVariants(pid, {
3933
+ count: count ?? 5,
3934
+ prompt_modifier,
3935
+ });
3936
+ return {
3937
+ content: [
3938
+ { type: "text", text: JSON.stringify(r, null, 2) },
3939
+ ],
3940
+ };
3941
+ }
3942
+ case "list_face_variants": {
3943
+ needPid();
3944
+ const r = await client.ifListVariants(pid);
3945
+ return {
3946
+ content: [
3947
+ { type: "text", text: JSON.stringify(r, null, 2) },
3948
+ ],
3949
+ };
3950
+ }
3951
+ case "search_voice_library": {
3952
+ const r = await client.ifSearchVoiceLibrary({ q: voice_query });
3953
+ return {
3954
+ content: [
3955
+ { type: "text", text: JSON.stringify(r, null, 2) },
3956
+ ],
3957
+ };
3958
+ }
3959
+ case "set_voice_library": {
3960
+ needPid();
3961
+ if (!voice_id)
3962
+ throw new Error("voice_id is required");
3963
+ const r = await client.ifSetVoiceLibrary(pid, {
3964
+ voice_id,
3965
+ name: voice_name,
3966
+ });
3967
+ return {
3968
+ content: [
3969
+ { type: "text", text: JSON.stringify(r, null, 2) },
3970
+ ],
3971
+ };
3972
+ }
3973
+ case "generate_voice_sample": {
3974
+ needPid();
3975
+ if (!voice_text)
3976
+ throw new Error("voice_text is required");
3977
+ const r = await client.ifVoiceSample(pid, voice_text);
3978
+ return {
3979
+ content: [
3980
+ { type: "text", text: JSON.stringify(r, null, 2) },
3981
+ ],
3982
+ };
3983
+ }
3984
+ case "update_bios": {
3985
+ needPid();
3986
+ const r = await client.ifUpdateBios(pid, {
3987
+ bios: bios ?? {},
3988
+ generate_with_llm,
3989
+ });
3990
+ return {
3991
+ content: [
3992
+ { type: "text", text: JSON.stringify(r, null, 2) },
3993
+ ],
3994
+ };
3995
+ }
3996
+ case "blotato_whoami": {
3997
+ const r = await client.ifBlotatoWhoami();
3998
+ return {
3999
+ content: [
4000
+ { type: "text", text: JSON.stringify(r, null, 2) },
4001
+ ],
4002
+ };
4003
+ }
4004
+ case "blotato_accounts": {
4005
+ const r = await client.ifBlotatoAccounts();
4006
+ return {
4007
+ content: [
4008
+ { type: "text", text: JSON.stringify(r, null, 2) },
4009
+ ],
4010
+ };
4011
+ }
4012
+ case "register_blotato_account": {
4013
+ needPid();
4014
+ if (!platform || !account_id)
4015
+ throw new Error("platform and account_id are required");
4016
+ const r = await client.ifRegisterBlotato(pid, platform, {
4017
+ account_id,
4018
+ page_id,
4019
+ board_id,
4020
+ handle,
4021
+ media_type,
4022
+ });
4023
+ return {
4024
+ content: [
4025
+ { type: "text", text: JSON.stringify(r, null, 2) },
4026
+ ],
4027
+ };
4028
+ }
4029
+ case "unregister_blotato_account": {
4030
+ needPid();
4031
+ if (!platform)
4032
+ throw new Error("platform is required");
4033
+ const r = await client.ifUnregisterBlotato(pid, platform);
4034
+ return {
4035
+ content: [
4036
+ { type: "text", text: JSON.stringify(r, null, 2) },
4037
+ ],
4038
+ };
4039
+ }
4040
+ default:
4041
+ throw new Error(`Unknown action: ${action}`);
4042
+ }
4043
+ }
4044
+ catch (err) {
4045
+ return {
4046
+ content: [{ type: "text", text: `mind_personas error: ${err}` }],
4047
+ isError: true,
4048
+ };
4049
+ }
4050
+ });
3527
4051
  return server;
3528
4052
  }
3529
4053
  //# sourceMappingURL=server.js.map