@vibesharingapp/mcp-server 0.4.2 → 0.6.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/index.js +400 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -59,8 +59,39 @@ class VibesharingClient {
|
|
|
59
59
|
async getPrototype(id) {
|
|
60
60
|
return this.request(`/api/prototypes/${id}`);
|
|
61
61
|
}
|
|
62
|
-
async getFeedback(projectId) {
|
|
63
|
-
|
|
62
|
+
async getFeedback(projectId, filters) {
|
|
63
|
+
const params = new URLSearchParams({ projectId });
|
|
64
|
+
if (filters?.status)
|
|
65
|
+
params.set("status", filters.status);
|
|
66
|
+
if (filters?.priority)
|
|
67
|
+
params.set("priority", filters.priority);
|
|
68
|
+
if (filters?.assigned_to)
|
|
69
|
+
params.set("assignedTo", filters.assigned_to);
|
|
70
|
+
return this.request(`/api/feedback?${params.toString()}`);
|
|
71
|
+
}
|
|
72
|
+
async triageFeedback(feedbackIds, updates) {
|
|
73
|
+
if (feedbackIds.length === 1) {
|
|
74
|
+
return this.request("/api/feedback", {
|
|
75
|
+
method: "PATCH",
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
feedbackId: feedbackIds[0],
|
|
78
|
+
status: updates.status,
|
|
79
|
+
priority: updates.priority,
|
|
80
|
+
assignedTo: updates.assigned_to,
|
|
81
|
+
resolutionNote: updates.resolution_note,
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return this.request("/api/feedback/bulk", {
|
|
86
|
+
method: "PATCH",
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
feedbackIds,
|
|
89
|
+
status: updates.status,
|
|
90
|
+
priority: updates.priority,
|
|
91
|
+
assignedTo: updates.assigned_to,
|
|
92
|
+
resolutionNote: updates.resolution_note,
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
64
95
|
}
|
|
65
96
|
async syncContext(projectId, content) {
|
|
66
97
|
return this.request("/api/context", {
|
|
@@ -133,6 +164,31 @@ class VibesharingClient {
|
|
|
133
164
|
method: "DELETE",
|
|
134
165
|
});
|
|
135
166
|
}
|
|
167
|
+
async generateFeedbackTopics(projectId, topics) {
|
|
168
|
+
return this.request("/api/feedback-topics", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
projectId,
|
|
172
|
+
topics,
|
|
173
|
+
source: "auto",
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async notifyFeedbackResolved(projectId, feedbackIds, deployUrl) {
|
|
178
|
+
return this.request("/api/feedback/notify-resolved", {
|
|
179
|
+
method: "POST",
|
|
180
|
+
body: JSON.stringify({ projectId, feedbackIds, deployUrl }),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async updateFeedbackBrief(projectId, brief, focus) {
|
|
184
|
+
const updates = { feedback_brief: brief };
|
|
185
|
+
if (focus)
|
|
186
|
+
updates.feedback_focus = focus;
|
|
187
|
+
return this.request(`/api/prototypes/${projectId}`, {
|
|
188
|
+
method: "PATCH",
|
|
189
|
+
body: JSON.stringify(updates),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
136
192
|
}
|
|
137
193
|
/**
|
|
138
194
|
* Simple fuzzy text matching. Scores based on:
|
|
@@ -178,20 +234,31 @@ function fuzzyMatch(query, items, getName, threshold = 0.3) {
|
|
|
178
234
|
.sort((a, b) => b.score - a.score);
|
|
179
235
|
}
|
|
180
236
|
// ---- Version tracking & What's New ----
|
|
181
|
-
const CURRENT_VERSION = "0.
|
|
237
|
+
const CURRENT_VERSION = "0.6.0";
|
|
182
238
|
const WHATS_NEW = {
|
|
183
|
-
"0.
|
|
184
|
-
"🆕 VibeSharing MCP v0.
|
|
239
|
+
"0.6.0": [
|
|
240
|
+
"🆕 VibeSharing MCP v0.6.0 — What's New:",
|
|
241
|
+
"",
|
|
242
|
+
"• Auto-generated feedback questions — After deploying, use generate_feedback_topics",
|
|
243
|
+
" to create 3-5 targeted questions that guide stakeholders toward useful feedback.",
|
|
244
|
+
" Questions are categorized by theme: vision alignment, feasibility, design fidelity,",
|
|
245
|
+
" or interaction design. Previous auto-generated questions are replaced on each deploy.",
|
|
246
|
+
"• Feedback briefs — Include a brief parameter to set context stakeholders see in the",
|
|
247
|
+
" Context tab. Also auto-extracted from ## Feedback Brief in CLAUDE.md at deploy time.",
|
|
248
|
+
].join("\n"),
|
|
249
|
+
"0.5.0": [
|
|
250
|
+
"🆕 VibeSharing MCP v0.5.0 — What's New:",
|
|
185
251
|
"",
|
|
186
|
-
"•
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"•
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"
|
|
193
|
-
"•
|
|
194
|
-
"
|
|
252
|
+
"• Feedback triage — get_feedback now supports status, priority, and assignee",
|
|
253
|
+
" filters. Use triage_feedback to update status (open/in_progress/resolved/",
|
|
254
|
+
" wont_fix/deferred), set priority, and assign feedback to team members.",
|
|
255
|
+
"• New tool: triage_feedback — Bulk update feedback items without leaving your editor.",
|
|
256
|
+
].join("\n"),
|
|
257
|
+
"0.4.0": [
|
|
258
|
+
"• resolve_target tool — Fuzzy-matches collection/project names.",
|
|
259
|
+
"• Named deployments — Set friendly Vercel URLs with deploy_name.",
|
|
260
|
+
"• Fuzzy search on list_collections and list_prototypes.",
|
|
261
|
+
"• Guardrails on deploy tools.",
|
|
195
262
|
].join("\n"),
|
|
196
263
|
};
|
|
197
264
|
function getWhatsNew() {
|
|
@@ -242,7 +309,7 @@ const client = new VibesharingClient(VIBESHARING_URL, VIBESHARING_TOKEN);
|
|
|
242
309
|
// Create MCP server
|
|
243
310
|
const server = new index_js_1.Server({
|
|
244
311
|
name: "vibesharing",
|
|
245
|
-
version: "0.
|
|
312
|
+
version: "0.6.0",
|
|
246
313
|
}, {
|
|
247
314
|
capabilities: {
|
|
248
315
|
tools: {},
|
|
@@ -319,7 +386,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
319
386
|
},
|
|
320
387
|
{
|
|
321
388
|
name: "get_feedback",
|
|
322
|
-
description: "Get feedback and comments for a specific prototype.
|
|
389
|
+
description: "Get feedback and comments for a specific prototype. Can filter by status (open, in_progress, resolved, wont_fix, deferred), priority (critical, high, medium, low), or assignee.",
|
|
323
390
|
inputSchema: {
|
|
324
391
|
type: "object",
|
|
325
392
|
properties: {
|
|
@@ -327,10 +394,96 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
327
394
|
type: "string",
|
|
328
395
|
description: "The VibeSharing project/prototype ID",
|
|
329
396
|
},
|
|
397
|
+
status: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "Filter by status: open, in_progress, resolved, wont_fix, deferred. Comma-separated for multiple.",
|
|
400
|
+
},
|
|
401
|
+
priority: {
|
|
402
|
+
type: "string",
|
|
403
|
+
description: "Filter by priority: critical, high, medium, low",
|
|
404
|
+
},
|
|
405
|
+
assigned_to: {
|
|
406
|
+
type: "string",
|
|
407
|
+
description: "Filter by assignee user ID, or 'unassigned' for unassigned feedback",
|
|
408
|
+
},
|
|
330
409
|
},
|
|
331
410
|
required: ["project_id"],
|
|
332
411
|
},
|
|
333
412
|
},
|
|
413
|
+
{
|
|
414
|
+
name: "triage_feedback",
|
|
415
|
+
description: "Update status, priority, or assignee on one or more feedback items. Use this to triage feedback from within your editor.",
|
|
416
|
+
inputSchema: {
|
|
417
|
+
type: "object",
|
|
418
|
+
properties: {
|
|
419
|
+
feedback_ids: {
|
|
420
|
+
type: "array",
|
|
421
|
+
items: { type: "string" },
|
|
422
|
+
description: "One or more feedback IDs to update",
|
|
423
|
+
},
|
|
424
|
+
status: {
|
|
425
|
+
type: "string",
|
|
426
|
+
enum: ["open", "in_progress", "resolved", "wont_fix", "deferred"],
|
|
427
|
+
description: "New status for the feedback items",
|
|
428
|
+
},
|
|
429
|
+
priority: {
|
|
430
|
+
type: "string",
|
|
431
|
+
enum: ["critical", "high", "medium", "low"],
|
|
432
|
+
description: "New priority for the feedback items. Omit to leave unchanged.",
|
|
433
|
+
},
|
|
434
|
+
assigned_to: {
|
|
435
|
+
type: "string",
|
|
436
|
+
description: "User ID to assign to. Use empty string to unassign.",
|
|
437
|
+
},
|
|
438
|
+
resolution_note: {
|
|
439
|
+
type: "string",
|
|
440
|
+
description: "Brief explanation of how the feedback was addressed (shown to the stakeholder). Only meaningful when status is resolved/wont_fix/deferred.",
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
required: ["feedback_ids"],
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
name: "close_feedback_loop",
|
|
448
|
+
description: "CALL THIS AFTER DEPLOYING when there is open feedback. Matches what you just built to open feedback items, resolves them with explanations, and notifies the original stakeholders with a personalized digest. The stakeholder sees exactly what happened to their feedback.\n\nFlow:\n1. Pull open feedback via get_feedback\n2. Look at what you built and match changes to feedback items\n3. Call this tool with the resolutions\n4. Stakeholders get email: 'Your feedback was addressed' with per-item explanations",
|
|
449
|
+
inputSchema: {
|
|
450
|
+
type: "object",
|
|
451
|
+
properties: {
|
|
452
|
+
project_id: {
|
|
453
|
+
type: "string",
|
|
454
|
+
description: "The VibeSharing prototype ID",
|
|
455
|
+
},
|
|
456
|
+
resolutions: {
|
|
457
|
+
type: "array",
|
|
458
|
+
items: {
|
|
459
|
+
type: "object",
|
|
460
|
+
properties: {
|
|
461
|
+
feedback_id: {
|
|
462
|
+
type: "string",
|
|
463
|
+
description: "The feedback item ID being resolved",
|
|
464
|
+
},
|
|
465
|
+
status: {
|
|
466
|
+
type: "string",
|
|
467
|
+
enum: ["resolved", "wont_fix", "deferred", "in_progress"],
|
|
468
|
+
description: "What happened: resolved (fixed), wont_fix (intentional), deferred (later), in_progress (started but not done)",
|
|
469
|
+
},
|
|
470
|
+
note: {
|
|
471
|
+
type: "string",
|
|
472
|
+
description: "Brief explanation of what changed or why it was deferred. This is shown directly to the stakeholder. Be specific: 'Nav restructured to separate admin and user flows' not 'Fixed the navigation'.",
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
required: ["feedback_id", "status", "note"],
|
|
476
|
+
},
|
|
477
|
+
description: "Array of feedback items to resolve with explanations",
|
|
478
|
+
},
|
|
479
|
+
deploy_url: {
|
|
480
|
+
type: "string",
|
|
481
|
+
description: "Optional: URL of the new deploy (included in notification so stakeholders can see the update)",
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
required: ["project_id", "resolutions"],
|
|
485
|
+
},
|
|
486
|
+
},
|
|
334
487
|
{
|
|
335
488
|
name: "sync_context",
|
|
336
489
|
description: "Sync your CLAUDE.md, AGENTS.md, or project context to VibeSharing. This helps maintain context across AI sessions and team members.",
|
|
@@ -583,6 +736,52 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
583
736
|
required: ["link_id"],
|
|
584
737
|
},
|
|
585
738
|
},
|
|
739
|
+
{
|
|
740
|
+
name: "generate_feedback_topics",
|
|
741
|
+
description: "Auto-generate feedback questions for a prototype based on what was built. IMPORTANT: Before generating questions, ask the user: 'What type of feedback is most important for this deploy?' and present these options:\n\n 1. Awareness only — just sharing progress, no feedback needed\n 2. Design direction — brand, visual, layout feedback\n 3. Technical feasibility — is this buildable, are these features doable\n 4. Vision alignment — does this match where we're going\n 5. Interaction design — usability, flow, UX patterns\n 6. Full review — all feedback welcome (default)\n\nUse their answer as the 'focus' parameter. If 'awareness', skip topic generation and just set the brief. Otherwise generate 3-5 questions, weighting toward the chosen focus theme.",
|
|
742
|
+
inputSchema: {
|
|
743
|
+
type: "object",
|
|
744
|
+
properties: {
|
|
745
|
+
project_id: {
|
|
746
|
+
type: "string",
|
|
747
|
+
description: "The VibeSharing prototype ID",
|
|
748
|
+
},
|
|
749
|
+
focus: {
|
|
750
|
+
type: "string",
|
|
751
|
+
enum: ["awareness", "design", "feasibility", "vision", "interaction", "full"],
|
|
752
|
+
description: "The type of feedback the designer wants. 'awareness' = no questions, just FYI. Others emphasize that theme. 'full' = all themes equally. Default: 'full'.",
|
|
753
|
+
},
|
|
754
|
+
brief: {
|
|
755
|
+
type: "string",
|
|
756
|
+
description: "A short (2-4 sentence) feedback brief explaining what this prototype is and what's ready for review. Stored on the prototype and shown to stakeholders in the Context tab.",
|
|
757
|
+
},
|
|
758
|
+
topics: {
|
|
759
|
+
type: "array",
|
|
760
|
+
items: {
|
|
761
|
+
type: "object",
|
|
762
|
+
properties: {
|
|
763
|
+
title: {
|
|
764
|
+
type: "string",
|
|
765
|
+
description: "The feedback question (e.g., 'Does this navigation flow match how your team actually works?')",
|
|
766
|
+
},
|
|
767
|
+
description: {
|
|
768
|
+
type: "string",
|
|
769
|
+
description: "Optional: Additional context for the question",
|
|
770
|
+
},
|
|
771
|
+
theme: {
|
|
772
|
+
type: "string",
|
|
773
|
+
enum: ["vision", "feasibility", "design", "interaction"],
|
|
774
|
+
description: "Question theme: 'vision' (alignment with goals), 'feasibility' (technical possibility), 'design' (brand/visual fidelity), 'interaction' (usability/UX patterns)",
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
required: ["title"],
|
|
778
|
+
},
|
|
779
|
+
description: "Array of feedback questions to create. Generate 3-5 based on what you built. Weight toward the focus theme (e.g., if focus is 'feasibility', 2-3 questions should be feasibility-themed). Not required when focus is 'awareness'.",
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
required: ["project_id"],
|
|
783
|
+
},
|
|
784
|
+
},
|
|
586
785
|
],
|
|
587
786
|
};
|
|
588
787
|
});
|
|
@@ -716,26 +915,35 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
716
915
|
};
|
|
717
916
|
}
|
|
718
917
|
case "get_feedback": {
|
|
719
|
-
const { project_id } = args;
|
|
720
|
-
const result = await client.getFeedback(project_id
|
|
918
|
+
const { project_id, status: statusFilter, priority: priorityFilter, assigned_to: assignedToFilter } = args;
|
|
919
|
+
const result = await client.getFeedback(project_id, {
|
|
920
|
+
status: statusFilter,
|
|
921
|
+
priority: priorityFilter,
|
|
922
|
+
assigned_to: assignedToFilter,
|
|
923
|
+
});
|
|
721
924
|
const feedback = result.feedback || [];
|
|
722
925
|
if (feedback.length === 0) {
|
|
926
|
+
const filterNote = statusFilter || priorityFilter || assignedToFilter
|
|
927
|
+
? " matching your filters"
|
|
928
|
+
: "";
|
|
723
929
|
return {
|
|
724
930
|
content: [
|
|
725
931
|
{
|
|
726
932
|
type: "text",
|
|
727
|
-
text:
|
|
933
|
+
text: `No feedback${filterNote} for this prototype. Share it with your team to get their thoughts!`,
|
|
728
934
|
},
|
|
729
935
|
],
|
|
730
936
|
};
|
|
731
937
|
}
|
|
732
938
|
const feedbackList = feedback
|
|
733
939
|
.map((f) => {
|
|
734
|
-
const
|
|
940
|
+
const itemStatus = f.status || (f.resolved_at ? "resolved" : "open");
|
|
941
|
+
const priorityLabel = f.priority ? ` [${f.priority.toUpperCase()}]` : "";
|
|
942
|
+
const assigneeLabel = f.assignee_name ? ` → ${f.assignee_name}` : "";
|
|
735
943
|
const replies = f.replies && f.replies.length > 0
|
|
736
944
|
? `\n Replies: ${f.replies.length}`
|
|
737
945
|
: "";
|
|
738
|
-
return `- ${f.user_name}
|
|
946
|
+
return `- [${itemStatus}]${priorityLabel}${assigneeLabel} ${f.user_name}: "${f.content}"\n ID: ${f.id}\n ${new Date(f.created_at).toLocaleDateString()}${replies}`;
|
|
739
947
|
})
|
|
740
948
|
.join("\n\n");
|
|
741
949
|
return {
|
|
@@ -747,6 +955,98 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
747
955
|
],
|
|
748
956
|
};
|
|
749
957
|
}
|
|
958
|
+
case "triage_feedback": {
|
|
959
|
+
const { feedback_ids, status: newStatus, priority: newPriority, assigned_to: newAssignee, resolution_note } = args;
|
|
960
|
+
if (!feedback_ids || feedback_ids.length === 0) {
|
|
961
|
+
return {
|
|
962
|
+
content: [{ type: "text", text: "Error: feedback_ids array is required" }],
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
const updates = {};
|
|
966
|
+
if (newStatus)
|
|
967
|
+
updates.status = newStatus;
|
|
968
|
+
if (newPriority !== undefined)
|
|
969
|
+
updates.priority = newPriority;
|
|
970
|
+
if (newAssignee !== undefined)
|
|
971
|
+
updates.assigned_to = newAssignee || null;
|
|
972
|
+
if (resolution_note)
|
|
973
|
+
updates.resolution_note = resolution_note;
|
|
974
|
+
const result = await client.triageFeedback(feedback_ids, updates);
|
|
975
|
+
const changes = [];
|
|
976
|
+
if (newStatus)
|
|
977
|
+
changes.push(`status → ${newStatus}`);
|
|
978
|
+
if (newPriority)
|
|
979
|
+
changes.push(`priority → ${newPriority}`);
|
|
980
|
+
if (newAssignee !== undefined)
|
|
981
|
+
changes.push(newAssignee ? `assigned → ${newAssignee}` : "unassigned");
|
|
982
|
+
if (resolution_note)
|
|
983
|
+
changes.push(`note: "${resolution_note}"`);
|
|
984
|
+
return {
|
|
985
|
+
content: [
|
|
986
|
+
{
|
|
987
|
+
type: "text",
|
|
988
|
+
text: `Updated ${feedback_ids.length} feedback item(s): ${changes.join(", ")}`,
|
|
989
|
+
},
|
|
990
|
+
],
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
case "close_feedback_loop": {
|
|
994
|
+
const { project_id, resolutions, deploy_url } = args;
|
|
995
|
+
if (!resolutions || resolutions.length === 0) {
|
|
996
|
+
return {
|
|
997
|
+
content: [{ type: "text", text: "Error: At least one resolution is required." }],
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
// Step 1: Resolve each feedback item with its note
|
|
1001
|
+
const resolvedIds = [];
|
|
1002
|
+
const errors = [];
|
|
1003
|
+
for (const res of resolutions) {
|
|
1004
|
+
try {
|
|
1005
|
+
await client.triageFeedback([res.feedback_id], {
|
|
1006
|
+
status: res.status,
|
|
1007
|
+
resolution_note: res.note,
|
|
1008
|
+
});
|
|
1009
|
+
resolvedIds.push(res.feedback_id);
|
|
1010
|
+
}
|
|
1011
|
+
catch (err) {
|
|
1012
|
+
errors.push(`Failed to update ${res.feedback_id}: ${err}`);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
// Step 2: Notify stakeholders
|
|
1016
|
+
let notifyResult = { notified: 0, emailed: 0, stakeholders: 0 };
|
|
1017
|
+
if (resolvedIds.length > 0) {
|
|
1018
|
+
try {
|
|
1019
|
+
notifyResult = await client.notifyFeedbackResolved(project_id, resolvedIds, deploy_url);
|
|
1020
|
+
}
|
|
1021
|
+
catch (err) {
|
|
1022
|
+
errors.push(`Notification failed: ${err}`);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
const statusLabels = {
|
|
1026
|
+
resolved: "Resolved",
|
|
1027
|
+
wont_fix: "Won't fix",
|
|
1028
|
+
deferred: "Deferred",
|
|
1029
|
+
in_progress: "In progress",
|
|
1030
|
+
};
|
|
1031
|
+
const lines = [
|
|
1032
|
+
`✅ Feedback loop closed — ${resolvedIds.length} item${resolvedIds.length === 1 ? "" : "s"} updated:`,
|
|
1033
|
+
"",
|
|
1034
|
+
...resolutions.map((r, i) => {
|
|
1035
|
+
const label = statusLabels[r.status] || r.status;
|
|
1036
|
+
const success = resolvedIds.includes(r.feedback_id) ? "✓" : "✗";
|
|
1037
|
+
return ` ${success} [${label}] ${r.note}`;
|
|
1038
|
+
}),
|
|
1039
|
+
];
|
|
1040
|
+
if (notifyResult.stakeholders > 0) {
|
|
1041
|
+
lines.push("", `📬 ${notifyResult.stakeholders} stakeholder${notifyResult.stakeholders === 1 ? "" : "s"} notified (${notifyResult.emailed} email${notifyResult.emailed === 1 ? "" : "s"} sent)`, "Each stakeholder received a personalized digest showing what happened to their specific feedback.");
|
|
1042
|
+
}
|
|
1043
|
+
if (errors.length > 0) {
|
|
1044
|
+
lines.push("", `⚠️ ${errors.length} error(s):`, ...errors.map(e => ` - ${e}`));
|
|
1045
|
+
}
|
|
1046
|
+
return {
|
|
1047
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
750
1050
|
case "sync_context": {
|
|
751
1051
|
const { project_id, content } = args;
|
|
752
1052
|
await client.syncContext(project_id, content);
|
|
@@ -1173,6 +1473,85 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
1173
1473
|
],
|
|
1174
1474
|
};
|
|
1175
1475
|
}
|
|
1476
|
+
case "generate_feedback_topics": {
|
|
1477
|
+
const { project_id, topics, brief, focus } = args;
|
|
1478
|
+
const feedbackFocus = focus || "full";
|
|
1479
|
+
const themeLabels = {
|
|
1480
|
+
vision: "Vision Alignment",
|
|
1481
|
+
feasibility: "Feasibility",
|
|
1482
|
+
design: "Design Fidelity",
|
|
1483
|
+
interaction: "Interaction Design",
|
|
1484
|
+
};
|
|
1485
|
+
const focusLabels = {
|
|
1486
|
+
awareness: "Awareness only",
|
|
1487
|
+
design: "Design direction",
|
|
1488
|
+
feasibility: "Technical feasibility",
|
|
1489
|
+
vision: "Vision alignment",
|
|
1490
|
+
interaction: "Interaction design",
|
|
1491
|
+
full: "Full review",
|
|
1492
|
+
};
|
|
1493
|
+
// Store brief and focus
|
|
1494
|
+
try {
|
|
1495
|
+
await client.updateFeedbackBrief(project_id, brief || "", feedbackFocus);
|
|
1496
|
+
}
|
|
1497
|
+
catch (err) {
|
|
1498
|
+
console.error("Failed to store feedback brief/focus:", err);
|
|
1499
|
+
}
|
|
1500
|
+
// Awareness mode: no questions, just the brief
|
|
1501
|
+
if (feedbackFocus === "awareness") {
|
|
1502
|
+
// Clear any existing auto-generated questions
|
|
1503
|
+
try {
|
|
1504
|
+
await client.generateFeedbackTopics(project_id, []);
|
|
1505
|
+
}
|
|
1506
|
+
catch {
|
|
1507
|
+
// OK if this fails — just means no old auto topics to clear
|
|
1508
|
+
}
|
|
1509
|
+
const lines = [
|
|
1510
|
+
`📢 Prototype set to awareness mode — no feedback questions will be shown.`,
|
|
1511
|
+
];
|
|
1512
|
+
if (brief) {
|
|
1513
|
+
lines.push("", `📋 Brief saved: "${brief.substring(0, 100)}${brief.length > 100 ? "..." : ""}"`);
|
|
1514
|
+
}
|
|
1515
|
+
lines.push("", "Stakeholders will see this as an FYI with the Context tab available.", "They can still leave general comments if they choose to.");
|
|
1516
|
+
return {
|
|
1517
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
// All other modes: generate questions
|
|
1521
|
+
if (!topics || topics.length === 0) {
|
|
1522
|
+
return {
|
|
1523
|
+
content: [{ type: "text", text: "Error: At least one topic is required when focus is not 'awareness'." }],
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
// Sort topics: focused theme first, then others
|
|
1527
|
+
const sortedTopics = feedbackFocus !== "full"
|
|
1528
|
+
? [
|
|
1529
|
+
...topics.filter(t => t.theme === feedbackFocus),
|
|
1530
|
+
...topics.filter(t => t.theme !== feedbackFocus),
|
|
1531
|
+
]
|
|
1532
|
+
: topics;
|
|
1533
|
+
const result = await client.generateFeedbackTopics(project_id, sortedTopics);
|
|
1534
|
+
const created = result.topics || [];
|
|
1535
|
+
const lines = [
|
|
1536
|
+
`✅ Created ${created.length} feedback question${created.length === 1 ? "" : "s"} (focus: ${focusLabels[feedbackFocus] || feedbackFocus}):`,
|
|
1537
|
+
"",
|
|
1538
|
+
...created.map((t, i) => {
|
|
1539
|
+
const tag = t.theme ? ` [${themeLabels[t.theme] || t.theme}]` : "";
|
|
1540
|
+
const star = t.theme === feedbackFocus ? " ★" : "";
|
|
1541
|
+
return ` ${i + 1}. ${t.title}${tag}${star}`;
|
|
1542
|
+
}),
|
|
1543
|
+
];
|
|
1544
|
+
if (brief) {
|
|
1545
|
+
lines.push("", `📋 Feedback brief saved — stakeholders can see it in the Context tab.`);
|
|
1546
|
+
}
|
|
1547
|
+
if (feedbackFocus !== "full") {
|
|
1548
|
+
lines.push("", `${themeLabels[feedbackFocus] || feedbackFocus} questions are pinned to the top for stakeholders.`);
|
|
1549
|
+
}
|
|
1550
|
+
lines.push("", "Previous auto-generated questions were replaced. Manual questions are untouched.");
|
|
1551
|
+
return {
|
|
1552
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1176
1555
|
default:
|
|
1177
1556
|
return {
|
|
1178
1557
|
content: [
|
package/package.json
CHANGED