@vailent/pulse-mcp 1.2.0 → 1.4.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/server.js +52 -18
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -40498,14 +40498,32 @@ async function handlePodMembers(params) {
40498
40498
  return ok(data, `${(data || []).length} members in pod`, (data || []).length);
40499
40499
  }
40500
40500
  case "add": {
40501
- const displayName = params.displayName;
40502
- if (!displayName?.trim()) return err("displayName is required", "MISSING_PARAM");
40503
- const initials = params.initials || displayName.split(" ").map((w) => w[0]).join("").toUpperCase().slice(0, 2);
40501
+ const userId = params.userId;
40502
+ let displayName = params.displayName;
40503
+ let initials = params.initials;
40504
+ let role = params.role || "engineer";
40505
+ if (userId) {
40506
+ const { data: user } = await supabase.from("users").select("full_name, job_title").eq("id", userId).single();
40507
+ if (!user) return err("User not found", "NOT_FOUND");
40508
+ if (!displayName) displayName = user.full_name;
40509
+ if (!initials) {
40510
+ initials = displayName.split(" ").map((w) => w[0]).join("").toUpperCase().slice(0, 2);
40511
+ }
40512
+ if (!params.role) {
40513
+ const jobTitles = user.job_title || ["member"];
40514
+ role = jobTitles.includes("product_lead") ? "product_lead" : jobTitles.includes("designer") ? "designer" : "engineer";
40515
+ }
40516
+ }
40517
+ if (!displayName?.trim()) return err("displayName is required (or provide userId)", "MISSING_PARAM");
40518
+ if (!initials) {
40519
+ initials = displayName.split(" ").map((w) => w[0]).join("").toUpperCase().slice(0, 2);
40520
+ }
40504
40521
  const { data, error: error2 } = await supabase.from("pod_members").insert({
40505
40522
  pod_id: podId,
40523
+ user_id: userId || null,
40506
40524
  display_name: displayName.trim(),
40507
40525
  initials,
40508
- role: params.role || "engineer"
40526
+ role
40509
40527
  }).select().single();
40510
40528
  if (error2) return err(error2.message);
40511
40529
  return ok(data, `Added ${displayName} to pod`);
@@ -40598,7 +40616,7 @@ function getGitEmail(scope) {
40598
40616
  async function lookupByEmail(supabase, email3) {
40599
40617
  const { data } = await supabase.from("users").select("id, email, full_name, job_title").eq("email", email3).limit(1).single();
40600
40618
  if (!data) return null;
40601
- return { id: data.id, email: data.email, fullName: data.full_name, jobTitle: data.job_title || "member" };
40619
+ return { id: data.id, email: data.email, fullName: data.full_name, jobTitle: data.job_title || ["member"] };
40602
40620
  }
40603
40621
 
40604
40622
  // tools/features.ts
@@ -40674,7 +40692,11 @@ async function handleFeatures(params) {
40674
40692
  weekStart: "week_start",
40675
40693
  size: "size",
40676
40694
  projectName: "project_name",
40677
- sortOrder: "sort_order"
40695
+ sortOrder: "sort_order",
40696
+ prdText: "prd_text",
40697
+ prdFileUrl: "prd_file_url",
40698
+ prdFileName: "prd_file_name",
40699
+ prdSummary: "prd_summary"
40678
40700
  };
40679
40701
  const updates = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
40680
40702
  for (const [key, col] of Object.entries(allowedFields)) {
@@ -40813,7 +40835,7 @@ async function handleRequests(params) {
40813
40835
  pod_id: podId,
40814
40836
  project_name: params.projectName || null,
40815
40837
  requester_name: params.requesterName || null,
40816
- source: params.source || "manual_ui",
40838
+ source: params.source || "mcp",
40817
40839
  type: params.requestType || "feature_request",
40818
40840
  priority: params.priority || null,
40819
40841
  sentiment: params.sentiment || null,
@@ -40891,7 +40913,7 @@ async function handleBugs(params) {
40891
40913
  description: params.description || null,
40892
40914
  pod_id: podId,
40893
40915
  project_name: params.projectName || null,
40894
- source: params.source || "manual_ui",
40916
+ source: params.source || "mcp",
40895
40917
  type: "bug",
40896
40918
  priority: params.priority || "medium",
40897
40919
  status: "open"
@@ -47470,7 +47492,9 @@ function formatWeekStart(date4) {
47470
47492
  async function handleBriefing(params) {
47471
47493
  const supabase = getAdminClient();
47472
47494
  const currentUser = await getCurrentUser();
47473
- const jobTitle = params.jobTitle || currentUser?.jobTitle || "engineer";
47495
+ const paramTitle = params.jobTitle;
47496
+ const jobTitles = paramTitle ? [paramTitle] : currentUser?.jobTitle || ["engineer"];
47497
+ const jobTitle = jobTitles.find((t) => t === "leadership") || jobTitles.find((t) => t === "product_lead") || jobTitles.find((t) => t === "designer") || jobTitles.find((t) => t === "engineer") || jobTitles.find((t) => t === "sales") || jobTitles[0] || "engineer";
47474
47498
  const podIds = params.podIds;
47475
47499
  const now = /* @__PURE__ */ new Date();
47476
47500
  const thisWeekStart = getWeekStart(now);
@@ -47539,7 +47563,7 @@ async function handleTeam(params) {
47539
47563
  id: u.id,
47540
47564
  email: u.email,
47541
47565
  fullName: u.full_name,
47542
- jobTitle: u.job_title || "member",
47566
+ jobTitle: u.job_title || ["member"],
47543
47567
  role: u.role,
47544
47568
  isActive: u.is_active,
47545
47569
  pods: userPods
@@ -47549,11 +47573,16 @@ async function handleTeam(params) {
47549
47573
  }
47550
47574
  case "update_role": {
47551
47575
  const userId = params.userId;
47552
- const jobTitle = params.jobTitle;
47553
- if (!userId || !jobTitle) return err("userId and jobTitle are required", "MISSING_PARAM");
47554
- const { error: error2 } = await supabase.from("users").update({ job_title: jobTitle, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", userId);
47576
+ const rawTitle = params.jobTitle;
47577
+ if (!userId || !rawTitle) return err("userId and jobTitle are required", "MISSING_PARAM");
47578
+ const titles = Array.isArray(rawTitle) ? rawTitle : [rawTitle];
47579
+ if (titles.length === 0) return err("At least one role is required", "INVALID_PARAM");
47580
+ const valid = ["product_lead", "engineer", "designer", "leadership", "sales", "member"];
47581
+ const invalid = titles.filter((t) => !valid.includes(t));
47582
+ if (invalid.length > 0) return err(`Invalid role(s): ${invalid.join(", ")}`, "INVALID_PARAM");
47583
+ const { error: error2 } = await supabase.from("users").update({ job_title: titles, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", userId);
47555
47584
  if (error2) return err(error2.message);
47556
- return ok({ userId, jobTitle }, `Updated role to ${jobTitle}`);
47585
+ return ok({ userId, jobTitle: titles }, `Updated roles to ${titles.join(", ")}`);
47557
47586
  }
47558
47587
  case "assign_pod": {
47559
47588
  const userId = params.userId;
@@ -47564,8 +47593,8 @@ async function handleTeam(params) {
47564
47593
  const { data: user } = await supabase.from("users").select("full_name, job_title").eq("id", userId).single();
47565
47594
  const displayName = user?.full_name || "Unknown";
47566
47595
  const initials = displayName.split(" ").map((w) => w[0]).join("").toUpperCase().slice(0, 2);
47567
- const roleMap = { product_lead: "product_lead", engineer: "engineer", designer: "designer" };
47568
- const podRole = roleMap[user?.job_title || ""] || "engineer";
47596
+ const jobTitles = user?.job_title || ["member"];
47597
+ const podRole = jobTitles.includes("product_lead") ? "product_lead" : jobTitles.includes("designer") ? "designer" : "engineer";
47569
47598
  await supabase.from("pod_members").insert({
47570
47599
  pod_id: podId,
47571
47600
  user_id: userId,
@@ -47609,6 +47638,7 @@ server.tool(
47609
47638
  action: external_exports4.enum(["list", "add", "update", "remove"]),
47610
47639
  podId: external_exports4.string().describe("Pod ID"),
47611
47640
  memberId: external_exports4.string().optional().describe("Member ID (for update/remove)"),
47641
+ userId: external_exports4.string().optional().describe("User ID \u2014 links pod member to a user (for add). Auto-populates name/initials/role from user."),
47612
47642
  displayName: external_exports4.string().optional().describe("Display name"),
47613
47643
  initials: external_exports4.string().optional().describe("2-letter initials"),
47614
47644
  role: external_exports4.string().optional().describe("Role: engineer, product_lead, designer")
@@ -47617,7 +47647,7 @@ server.tool(
47617
47647
  );
47618
47648
  server.tool(
47619
47649
  "pulse_features",
47620
- "Manage features and tasks. Actions: list (filter by pod/workstream/week/status/size), get, create (feature or task via size param), update (phase/step/status/blocker/week), delete, add_note, reorder.",
47650
+ "Manage features and tasks. Actions: list (filter by pod/workstream/week/status/size), get, create (feature or task via size param), update (phase/step/status/blocker/week/prdText/prdFileUrl), delete, add_note, reorder.",
47621
47651
  {
47622
47652
  action: external_exports4.enum(["list", "get", "create", "update", "delete", "add_note", "reorder"]),
47623
47653
  featureId: external_exports4.string().optional().describe("Feature ID"),
@@ -47634,6 +47664,10 @@ server.tool(
47634
47664
  blockerText: external_exports4.string().optional().describe("Blocker description"),
47635
47665
  sortOrder: external_exports4.number().optional().describe("Sort order for drag-to-reorder"),
47636
47666
  projectColor: external_exports4.string().optional().describe("Project color hex"),
47667
+ prdText: external_exports4.string().optional().describe("PRD text content (for update)"),
47668
+ prdFileUrl: external_exports4.string().optional().describe("PRD file URL (for update)"),
47669
+ prdFileName: external_exports4.string().optional().describe("PRD file name (for update)"),
47670
+ prdSummary: external_exports4.string().optional().describe("AI-generated PRD summary (for update)"),
47637
47671
  note: external_exports4.string().optional().describe("Note text (for add_note)"),
47638
47672
  items: external_exports4.array(external_exports4.object({ id: external_exports4.string(), sortOrder: external_exports4.number() })).optional().describe("Items to reorder"),
47639
47673
  limit: external_exports4.number().optional().describe("Max results")
@@ -47749,7 +47783,7 @@ server.tool(
47749
47783
  {
47750
47784
  action: external_exports4.enum(["list", "update_role", "assign_pod"]),
47751
47785
  userId: external_exports4.string().optional().describe("User ID"),
47752
- jobTitle: external_exports4.string().optional().describe("Job title: product_lead, engineer, designer, leadership, sales, member"),
47786
+ jobTitle: external_exports4.union([external_exports4.string(), external_exports4.array(external_exports4.string())]).optional().describe("Job title(s): product_lead, engineer, designer, leadership, sales, member. Accepts single string or array."),
47753
47787
  podId: external_exports4.string().optional().nullable().describe("Pod ID (null to remove from pods)")
47754
47788
  },
47755
47789
  async (params) => handleTeam(params)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vailent/pulse-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Pulse MCP server — manage pods, features, workstreams, bugs, and more from Claude Code",
5
5
  "type": "module",
6
6
  "bin": {