@vailent/pulse-mcp 1.8.0 → 1.9.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 +82 -12
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -41869,35 +41869,102 @@ async function handleWorkstreams(params) {
|
|
|
41869
41869
|
const action = params.action;
|
|
41870
41870
|
switch (action) {
|
|
41871
41871
|
case "list": {
|
|
41872
|
-
let query = supabase.from("projects").select("
|
|
41873
|
-
if (params.podId) query = query.eq("pod_id", params.podId);
|
|
41872
|
+
let query = supabase.from("projects").select("*, project_pods(pod_id, is_primary)").order("name");
|
|
41874
41873
|
if (params.status) query = query.eq("status", params.status);
|
|
41875
41874
|
else query = query.eq("status", "active");
|
|
41876
41875
|
const { data, error: error2 } = await query;
|
|
41877
41876
|
if (error2) return err(error2.message);
|
|
41878
|
-
|
|
41877
|
+
let results = data || [];
|
|
41878
|
+
if (params.podId) {
|
|
41879
|
+
results = results.filter((p) => {
|
|
41880
|
+
const pp = p.project_pods || [];
|
|
41881
|
+
return pp.some((r) => r.pod_id === params.podId) || p.pod_id === params.podId;
|
|
41882
|
+
});
|
|
41883
|
+
}
|
|
41884
|
+
return ok(results, `${results.length} workstreams`, results.length);
|
|
41879
41885
|
}
|
|
41880
41886
|
case "get": {
|
|
41881
41887
|
const slug = params.slug;
|
|
41882
41888
|
if (!slug) return err("slug is required", "MISSING_PARAM");
|
|
41883
|
-
const { data, error: error2 } = await supabase.from("projects").select("
|
|
41889
|
+
const { data, error: error2 } = await supabase.from("projects").select("*, project_pods(pod_id, is_primary)").eq("slug", slug).single();
|
|
41884
41890
|
if (error2 || !data) return err("Workstream not found", "NOT_FOUND");
|
|
41885
41891
|
return ok(data, `Workstream: ${data.name}`);
|
|
41886
41892
|
}
|
|
41887
41893
|
case "create": {
|
|
41888
41894
|
const name = params.name;
|
|
41895
|
+
const podId = params.podId;
|
|
41896
|
+
const mode = params.mode;
|
|
41889
41897
|
if (!name?.trim()) return err("name is required", "MISSING_PARAM");
|
|
41890
|
-
const
|
|
41898
|
+
const trimmedName = name.trim();
|
|
41899
|
+
const { data: existing } = await supabase.from("projects").select("id, name, slug, project_pods(pod_id)").eq("name", trimmedName).maybeSingle();
|
|
41900
|
+
if (existing && !mode) {
|
|
41901
|
+
const existingPodIds = existing.project_pods?.map((r) => r.pod_id) || [];
|
|
41902
|
+
if (podId && existingPodIds.includes(podId)) {
|
|
41903
|
+
return ok(existing, `Workstream "${trimmedName}" already linked to this pod`);
|
|
41904
|
+
}
|
|
41905
|
+
return ok(
|
|
41906
|
+
{ conflict: true, existingProject: { id: existing.id, name: existing.name, slug: existing.slug, podIds: existingPodIds } },
|
|
41907
|
+
`Workstream "${trimmedName}" already exists in another pod. Use mode: "link" to share or mode: "create_new" to create a separate one.`
|
|
41908
|
+
);
|
|
41909
|
+
}
|
|
41910
|
+
if (existing && mode === "link") {
|
|
41911
|
+
if (!podId) return err("podId is required to link", "MISSING_PARAM");
|
|
41912
|
+
await supabase.from("project_pods").insert({ project_id: existing.id, pod_id: podId, is_primary: false });
|
|
41913
|
+
return ok(existing, `Linked "${trimmedName}" to pod`);
|
|
41914
|
+
}
|
|
41915
|
+
if (existing && mode === "create_new") {
|
|
41916
|
+
const { data: pod } = podId ? await supabase.from("pods").select("name").eq("id", podId).single() : { data: null };
|
|
41917
|
+
const suffix = pod?.name || podId || "";
|
|
41918
|
+
const newName = suffix ? `${trimmedName} (${suffix})` : trimmedName;
|
|
41919
|
+
const newSlug = newName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
41920
|
+
const { data: data2, error: error3 } = await supabase.from("projects").insert({
|
|
41921
|
+
name: newName,
|
|
41922
|
+
slug: newSlug,
|
|
41923
|
+
description: params.description || null,
|
|
41924
|
+
pod_id: podId || null,
|
|
41925
|
+
color: params.color || "#71717a",
|
|
41926
|
+
status: "active"
|
|
41927
|
+
}).select().single();
|
|
41928
|
+
if (error3) return err(error3.message);
|
|
41929
|
+
if (podId) await supabase.from("project_pods").insert({ project_id: data2.id, pod_id: podId, is_primary: true });
|
|
41930
|
+
return ok(data2, `Created separate workstream: ${newName}`);
|
|
41931
|
+
}
|
|
41932
|
+
const slug = trimmedName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
41891
41933
|
const { data, error: error2 } = await supabase.from("projects").insert({
|
|
41892
|
-
name:
|
|
41934
|
+
name: trimmedName,
|
|
41893
41935
|
slug,
|
|
41894
41936
|
description: params.description || null,
|
|
41895
|
-
pod_id:
|
|
41937
|
+
pod_id: podId || null,
|
|
41896
41938
|
color: params.color || "#71717a",
|
|
41897
41939
|
status: "active"
|
|
41898
41940
|
}).select().single();
|
|
41899
41941
|
if (error2) return err(error2.message);
|
|
41900
|
-
|
|
41942
|
+
if (podId) await supabase.from("project_pods").insert({ project_id: data.id, pod_id: podId, is_primary: true });
|
|
41943
|
+
return ok(data, `Created workstream: ${trimmedName}`);
|
|
41944
|
+
}
|
|
41945
|
+
case "link": {
|
|
41946
|
+
const slug = params.slug;
|
|
41947
|
+
const podId = params.podId;
|
|
41948
|
+
if (!slug || !podId) return err("slug and podId are required", "MISSING_PARAM");
|
|
41949
|
+
const { data: project } = await supabase.from("projects").select("id, name").eq("slug", slug).single();
|
|
41950
|
+
if (!project) return err("Workstream not found", "NOT_FOUND");
|
|
41951
|
+
const { error: error2 } = await supabase.from("project_pods").insert({
|
|
41952
|
+
project_id: project.id,
|
|
41953
|
+
pod_id: podId,
|
|
41954
|
+
is_primary: false
|
|
41955
|
+
});
|
|
41956
|
+
if (error2) return err(error2.message);
|
|
41957
|
+
return ok({ projectId: project.id, podId }, `Linked "${project.name}" to pod`);
|
|
41958
|
+
}
|
|
41959
|
+
case "unlink": {
|
|
41960
|
+
const slug = params.slug;
|
|
41961
|
+
const podId = params.podId;
|
|
41962
|
+
if (!slug || !podId) return err("slug and podId are required", "MISSING_PARAM");
|
|
41963
|
+
const { data: project } = await supabase.from("projects").select("id, name").eq("slug", slug).single();
|
|
41964
|
+
if (!project) return err("Workstream not found", "NOT_FOUND");
|
|
41965
|
+
const { error: error2 } = await supabase.from("project_pods").delete().eq("project_id", project.id).eq("pod_id", podId);
|
|
41966
|
+
if (error2) return err(error2.message);
|
|
41967
|
+
return ok({ projectId: project.id, podId }, `Unlinked "${project.name}" from pod`);
|
|
41901
41968
|
}
|
|
41902
41969
|
case "update": {
|
|
41903
41970
|
const slug = params.slug;
|
|
@@ -41954,6 +42021,7 @@ async function handleRequests(params) {
|
|
|
41954
42021
|
const title = params.title;
|
|
41955
42022
|
if (!podId || !title?.trim()) return err("podId and title are required", "MISSING_PARAM");
|
|
41956
42023
|
const { data, error: error2 } = await supabase.from("work_items").insert({
|
|
42024
|
+
id: `f-${Date.now().toString(36)}`,
|
|
41957
42025
|
title: title.trim(),
|
|
41958
42026
|
description: params.description || null,
|
|
41959
42027
|
pod_id: podId,
|
|
@@ -42033,6 +42101,7 @@ async function handleBugs(params) {
|
|
|
42033
42101
|
const title = params.title;
|
|
42034
42102
|
if (!podId || !title?.trim()) return err("podId and title are required", "MISSING_PARAM");
|
|
42035
42103
|
const { data, error: error2 } = await supabase.from("work_items").insert({
|
|
42104
|
+
id: `f-${Date.now().toString(36)}`,
|
|
42036
42105
|
title: title.trim(),
|
|
42037
42106
|
description: params.description || null,
|
|
42038
42107
|
pod_id: podId,
|
|
@@ -47397,15 +47466,16 @@ server.tool(
|
|
|
47397
47466
|
);
|
|
47398
47467
|
server.tool(
|
|
47399
47468
|
"pulse_workstreams",
|
|
47400
|
-
"Manage workstreams (project containers). Actions: list, get (by slug), create
|
|
47469
|
+
"Manage workstreams (project containers). Actions: list, get (by slug), create (detects name conflicts \u2014 use mode 'link' to share or 'create_new' for separate), link (add pod to existing workstream), unlink (remove pod from workstream), update, delete, get_suggestions.",
|
|
47401
47470
|
{
|
|
47402
|
-
action: external_exports.enum(["list", "get", "create", "update", "delete", "get_suggestions"]),
|
|
47471
|
+
action: external_exports.enum(["list", "get", "create", "update", "delete", "get_suggestions", "link", "unlink"]),
|
|
47403
47472
|
slug: external_exports.string().optional().describe("Workstream slug"),
|
|
47404
|
-
podId: external_exports.string().optional().describe("Pod ID filter"),
|
|
47473
|
+
podId: external_exports.string().optional().describe("Pod ID filter / target pod for link/unlink"),
|
|
47405
47474
|
name: external_exports.string().optional().describe("Workstream name"),
|
|
47406
47475
|
description: external_exports.string().optional().describe("Description"),
|
|
47407
47476
|
color: external_exports.string().optional().describe("Hex color"),
|
|
47408
|
-
status: external_exports.string().optional().describe("Status: active, archived, completed")
|
|
47477
|
+
status: external_exports.string().optional().describe("Status: active, archived, completed"),
|
|
47478
|
+
mode: external_exports.enum(["link", "create_new"]).optional().describe("When creating with a conflicting name: 'link' to share or 'create_new' for separate")
|
|
47409
47479
|
},
|
|
47410
47480
|
async (params) => handleWorkstreams(params)
|
|
47411
47481
|
);
|