@vailent/pulse-mcp 1.8.1 → 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 +80 -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;
|
|
@@ -47399,15 +47466,16 @@ server.tool(
|
|
|
47399
47466
|
);
|
|
47400
47467
|
server.tool(
|
|
47401
47468
|
"pulse_workstreams",
|
|
47402
|
-
"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.",
|
|
47403
47470
|
{
|
|
47404
|
-
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"]),
|
|
47405
47472
|
slug: external_exports.string().optional().describe("Workstream slug"),
|
|
47406
|
-
podId: external_exports.string().optional().describe("Pod ID filter"),
|
|
47473
|
+
podId: external_exports.string().optional().describe("Pod ID filter / target pod for link/unlink"),
|
|
47407
47474
|
name: external_exports.string().optional().describe("Workstream name"),
|
|
47408
47475
|
description: external_exports.string().optional().describe("Description"),
|
|
47409
47476
|
color: external_exports.string().optional().describe("Hex color"),
|
|
47410
|
-
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")
|
|
47411
47479
|
},
|
|
47412
47480
|
async (params) => handleWorkstreams(params)
|
|
47413
47481
|
);
|