@ourroadmaps/mcp 0.30.0 → 0.31.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 +377 -60
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -280,6 +280,7 @@ var audienceSchema = z2.object({
|
|
|
280
280
|
id: z2.string().uuid(),
|
|
281
281
|
organizationId: z2.string(),
|
|
282
282
|
name: z2.string(),
|
|
283
|
+
type: z2.enum(["stakeholder", "persona"]).nullable(),
|
|
283
284
|
description: z2.string().nullable(),
|
|
284
285
|
order: z2.number().int(),
|
|
285
286
|
createdAt: z2.string(),
|
|
@@ -614,6 +615,8 @@ var roadmapSchema = z11.object({
|
|
|
614
615
|
title: z11.string(),
|
|
615
616
|
horizon: horizonSchema.nullable(),
|
|
616
617
|
status: roadmapStatusSchema.nullable(),
|
|
618
|
+
phase: z11.string().nullable(),
|
|
619
|
+
phaseStep: z11.string().nullable(),
|
|
617
620
|
value: effortSchema.nullable(),
|
|
618
621
|
effort: effortSchema.nullable(),
|
|
619
622
|
order: z11.number().int(),
|
|
@@ -773,13 +776,8 @@ var SLIDE_TYPES = [
|
|
|
773
776
|
"title",
|
|
774
777
|
"section_header",
|
|
775
778
|
"bullets",
|
|
776
|
-
"two_column",
|
|
777
|
-
"comparison",
|
|
778
|
-
"timeline",
|
|
779
779
|
"image",
|
|
780
|
-
"quote",
|
|
781
780
|
"code",
|
|
782
|
-
"thank_you",
|
|
783
781
|
"mermaid",
|
|
784
782
|
"paragraph"
|
|
785
783
|
];
|
|
@@ -796,46 +794,17 @@ var bulletsContentSchema = z13.object({
|
|
|
796
794
|
title: z13.string().optional(),
|
|
797
795
|
items: z13.array(z13.string()).default([])
|
|
798
796
|
});
|
|
799
|
-
var twoColumnContentSchema = z13.object({
|
|
800
|
-
title: z13.string().optional(),
|
|
801
|
-
left: z13.string().default(""),
|
|
802
|
-
right: z13.string().default("")
|
|
803
|
-
});
|
|
804
|
-
var comparisonContentSchema = z13.object({
|
|
805
|
-
leftLabel: z13.string().default(""),
|
|
806
|
-
leftContent: z13.string().default(""),
|
|
807
|
-
rightLabel: z13.string().default(""),
|
|
808
|
-
rightContent: z13.string().default("")
|
|
809
|
-
});
|
|
810
|
-
var timelineStepSchema = z13.object({
|
|
811
|
-
title: z13.string(),
|
|
812
|
-
description: z13.string().optional()
|
|
813
|
-
});
|
|
814
|
-
var timelineContentSchema = z13.object({
|
|
815
|
-
title: z13.string().optional(),
|
|
816
|
-
steps: z13.array(timelineStepSchema).default([])
|
|
817
|
-
});
|
|
818
797
|
var imageContentSchema = z13.object({
|
|
819
798
|
title: z13.string().optional(),
|
|
820
799
|
imageUrl: z13.string().optional(),
|
|
821
800
|
caption: z13.string().optional()
|
|
822
801
|
});
|
|
823
|
-
var quoteContentSchema = z13.object({
|
|
824
|
-
quote: z13.string().default(""),
|
|
825
|
-
attribution: z13.string().optional()
|
|
826
|
-
});
|
|
827
802
|
var codeContentSchema = z13.object({
|
|
828
803
|
title: z13.string().optional(),
|
|
829
804
|
code: z13.string().default(""),
|
|
830
805
|
language: z13.string().optional(),
|
|
831
806
|
highlightLines: z13.array(z13.number()).optional()
|
|
832
807
|
});
|
|
833
|
-
var thankYouContentSchema = z13.object({
|
|
834
|
-
title: z13.string().default("Thank You"),
|
|
835
|
-
subtitle: z13.string().optional(),
|
|
836
|
-
ctaText: z13.string().optional(),
|
|
837
|
-
ctaUrl: z13.string().optional()
|
|
838
|
-
});
|
|
839
808
|
var mermaidContentSchema = z13.object({
|
|
840
809
|
title: z13.string().optional(),
|
|
841
810
|
code: z13.string().default("")
|
|
@@ -848,13 +817,8 @@ var typedSlideContentSchema = z13.discriminatedUnion("type", [
|
|
|
848
817
|
z13.object({ type: z13.literal("title"), ...titleContentSchema.shape }),
|
|
849
818
|
z13.object({ type: z13.literal("section_header"), ...sectionHeaderContentSchema.shape }),
|
|
850
819
|
z13.object({ type: z13.literal("bullets"), ...bulletsContentSchema.shape }),
|
|
851
|
-
z13.object({ type: z13.literal("two_column"), ...twoColumnContentSchema.shape }),
|
|
852
|
-
z13.object({ type: z13.literal("comparison"), ...comparisonContentSchema.shape }),
|
|
853
|
-
z13.object({ type: z13.literal("timeline"), ...timelineContentSchema.shape }),
|
|
854
820
|
z13.object({ type: z13.literal("image"), ...imageContentSchema.shape }),
|
|
855
|
-
z13.object({ type: z13.literal("quote"), ...quoteContentSchema.shape }),
|
|
856
821
|
z13.object({ type: z13.literal("code"), ...codeContentSchema.shape }),
|
|
857
|
-
z13.object({ type: z13.literal("thank_you"), ...thankYouContentSchema.shape }),
|
|
858
822
|
z13.object({ type: z13.literal("mermaid"), ...mermaidContentSchema.shape }),
|
|
859
823
|
z13.object({ type: z13.literal("paragraph"), ...paragraphContentSchema.shape })
|
|
860
824
|
]);
|
|
@@ -980,6 +944,18 @@ var updateBrainstormNotesInput = {
|
|
|
980
944
|
roadmapId: idField("roadmap item"),
|
|
981
945
|
notes: z15.string().describe("The brainstorm notes content")
|
|
982
946
|
};
|
|
947
|
+
var presentOptionsInput = {
|
|
948
|
+
question: z15.string().describe("The decision or question being presented to the user"),
|
|
949
|
+
options: z15.array(z15.object({
|
|
950
|
+
key: z15.string().describe("Short key like A, B, C"),
|
|
951
|
+
title: z15.string().describe("Option title"),
|
|
952
|
+
description: z15.string().describe("1-2 sentence description of the option")
|
|
953
|
+
})).min(2).max(5).describe("The options to present (2-5)"),
|
|
954
|
+
recommendation: z15.object({
|
|
955
|
+
key: z15.string().describe("Key of the recommended option"),
|
|
956
|
+
reason: z15.string().describe("Brief reason for the recommendation")
|
|
957
|
+
}).optional().describe("Which option is recommended and why")
|
|
958
|
+
};
|
|
983
959
|
var searchFeaturesInput = {
|
|
984
960
|
query: z15.string().optional().describe("Search query to match against name"),
|
|
985
961
|
type: featureTypeSchema.optional().describe("Filter by type (feature or area)")
|
|
@@ -1086,16 +1062,7 @@ var deleteAudienceInput = {
|
|
|
1086
1062
|
var getHistoryInput = {
|
|
1087
1063
|
startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
|
|
1088
1064
|
endDate: yyyyMmDdField("End date in YYYY-MM-DD format"),
|
|
1089
|
-
entityType: z15.enum([
|
|
1090
|
-
"roadmap",
|
|
1091
|
-
"feature",
|
|
1092
|
-
"idea",
|
|
1093
|
-
"prd",
|
|
1094
|
-
"wireframe",
|
|
1095
|
-
"product",
|
|
1096
|
-
"audience",
|
|
1097
|
-
"scenario"
|
|
1098
|
-
]).optional().describe("Filter to specific entity type")
|
|
1065
|
+
entityType: z15.enum(["roadmap", "feature", "idea", "prd", "wireframe", "product", "audience", "scenario"]).optional().describe("Filter to specific entity type")
|
|
1099
1066
|
};
|
|
1100
1067
|
var getHistorySummaryInput = {
|
|
1101
1068
|
startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
|
|
@@ -1140,7 +1107,18 @@ var createInitiativeInput = {
|
|
|
1140
1107
|
horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")'),
|
|
1141
1108
|
dateGranularity: dateGranularitySchema.optional().describe("Target date granularity: day, month, quarter, half-year, or year"),
|
|
1142
1109
|
dateValue: z15.string().optional().describe('Target date value matching granularity (e.g., "2024-Q1", "2024-03")'),
|
|
1143
|
-
targetDate: z15.string().optional().describe("Target date in YYYY-MM-DD format")
|
|
1110
|
+
targetDate: z15.string().optional().describe("Target date in YYYY-MM-DD format"),
|
|
1111
|
+
status: z15.enum(["on_track", "at_risk", "blocked", "paused"]).optional().describe("Project health status"),
|
|
1112
|
+
value: z15.number().int().min(1).max(3).optional().describe("Value rating (1-3 stars)"),
|
|
1113
|
+
effort: z15.enum(["xs", "s", "m", "l", "xl"]).optional().describe("Effort estimate (t-shirt size)"),
|
|
1114
|
+
target: z15.object({
|
|
1115
|
+
granularity: dateGranularitySchema,
|
|
1116
|
+
value: z15.string()
|
|
1117
|
+
}).optional().describe("Flexible target date"),
|
|
1118
|
+
deadline: z15.object({
|
|
1119
|
+
granularity: dateGranularitySchema,
|
|
1120
|
+
value: z15.string()
|
|
1121
|
+
}).optional().describe("Flexible deadline date")
|
|
1144
1122
|
};
|
|
1145
1123
|
var updateInitiativeInput = {
|
|
1146
1124
|
id: idField("initiative to update"),
|
|
@@ -1150,7 +1128,18 @@ var updateInitiativeInput = {
|
|
|
1150
1128
|
dateGranularity: dateGranularitySchema.nullable().optional().describe("New target date granularity (null to clear)"),
|
|
1151
1129
|
dateValue: z15.string().nullable().optional().describe("New target date value (null to clear)"),
|
|
1152
1130
|
targetDate: z15.string().nullable().optional().describe("New target date in YYYY-MM-DD format (null to clear)"),
|
|
1153
|
-
order: z15.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)")
|
|
1131
|
+
order: z15.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
|
|
1132
|
+
status: z15.enum(["on_track", "at_risk", "blocked", "paused"]).nullable().optional().describe("Project health status (null to clear)"),
|
|
1133
|
+
value: z15.number().int().min(1).max(3).nullable().optional().describe("Value rating (null to clear)"),
|
|
1134
|
+
effort: z15.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Effort estimate (null to clear)"),
|
|
1135
|
+
target: z15.object({
|
|
1136
|
+
granularity: dateGranularitySchema,
|
|
1137
|
+
value: z15.string()
|
|
1138
|
+
}).nullable().optional().describe("Flexible target date (null to clear)"),
|
|
1139
|
+
deadline: z15.object({
|
|
1140
|
+
granularity: dateGranularitySchema,
|
|
1141
|
+
value: z15.string()
|
|
1142
|
+
}).nullable().optional().describe("Flexible deadline date (null to clear)")
|
|
1154
1143
|
};
|
|
1155
1144
|
var deleteInitiativeInput = {
|
|
1156
1145
|
id: idField("initiative to delete")
|
|
@@ -1189,7 +1178,7 @@ var uploadProductDesignMediaInput = {
|
|
|
1189
1178
|
filePath: z15.string().describe("Absolute path to the image or video file on disk"),
|
|
1190
1179
|
description: z15.string().optional().describe("Optional description of the media")
|
|
1191
1180
|
};
|
|
1192
|
-
var
|
|
1181
|
+
var updateProductDesignMediaInput = {
|
|
1193
1182
|
productId: idField("product"),
|
|
1194
1183
|
mediaId: idField("design media"),
|
|
1195
1184
|
description: z15.string().nullable().describe("New description for the media")
|
|
@@ -1238,6 +1227,44 @@ var resolveFeedbackCommentInput = {
|
|
|
1238
1227
|
sessionId: uuidField("feedback session"),
|
|
1239
1228
|
commentId: uuidField("comment to resolve/unresolve")
|
|
1240
1229
|
};
|
|
1230
|
+
var createPresentationFeedbackSessionInput = {
|
|
1231
|
+
presentationId: uuidField("presentation"),
|
|
1232
|
+
variantId: uuidField("variant to create feedback session for"),
|
|
1233
|
+
message: z15.string().optional().describe("Message shown to reviewers"),
|
|
1234
|
+
expiresInDays: z15.number().int().min(1).max(90).optional().describe("Number of days until the session expires (default 14)")
|
|
1235
|
+
};
|
|
1236
|
+
var listPresentationFeedbackSessionsInput = {
|
|
1237
|
+
presentationId: uuidField("presentation"),
|
|
1238
|
+
variantId: uuidField("variant")
|
|
1239
|
+
};
|
|
1240
|
+
var getPresentationFeedbackSummaryInput = {
|
|
1241
|
+
presentationId: uuidField("presentation"),
|
|
1242
|
+
variantId: uuidField("variant"),
|
|
1243
|
+
sessionId: uuidField("feedback session"),
|
|
1244
|
+
filter: z15.enum(["all", "unresolved", "resolved"]).optional().describe("Filter by resolved status (default: unresolved)")
|
|
1245
|
+
};
|
|
1246
|
+
var getPresentationFeedbackDetailInput = {
|
|
1247
|
+
presentationId: uuidField("presentation"),
|
|
1248
|
+
variantId: uuidField("variant"),
|
|
1249
|
+
sessionId: uuidField("feedback session"),
|
|
1250
|
+
feedbackId: z15.string().uuid().optional().describe("Optional: get detail for a single feedback item"),
|
|
1251
|
+
filter: z15.enum(["all", "unresolved", "resolved"]).optional().describe("Filter by resolved status (default: all). Ignored if feedbackId provided.")
|
|
1252
|
+
};
|
|
1253
|
+
var resolvePresentationFeedbackInput = {
|
|
1254
|
+
presentationId: uuidField("presentation"),
|
|
1255
|
+
variantId: uuidField("variant"),
|
|
1256
|
+
sessionId: uuidField("feedback session"),
|
|
1257
|
+
feedbackId: uuidField("feedback item to resolve/unresolve"),
|
|
1258
|
+
type: z15.enum(["slide", "overall"]).describe("Type of feedback item"),
|
|
1259
|
+
resolved: z15.boolean().describe("Set to true to resolve, false to unresolve")
|
|
1260
|
+
};
|
|
1261
|
+
var addPresentationReviewerInput = {
|
|
1262
|
+
presentationId: uuidField("presentation"),
|
|
1263
|
+
variantId: uuidField("variant"),
|
|
1264
|
+
sessionId: uuidField("feedback session"),
|
|
1265
|
+
name: z15.string().min(1).max(200).describe("Reviewer name"),
|
|
1266
|
+
email: z15.string().email().optional().describe("Reviewer email")
|
|
1267
|
+
};
|
|
1241
1268
|
var searchExportsInput = {
|
|
1242
1269
|
roadmapId: z15.string().uuid().optional().describe("Filter by roadmap item ID"),
|
|
1243
1270
|
externalSystem: externalSystemSchema.optional().describe("Filter by external system"),
|
|
@@ -1327,8 +1354,8 @@ var getSlideInput = {
|
|
|
1327
1354
|
};
|
|
1328
1355
|
var createSlideInput = {
|
|
1329
1356
|
variantId: idField("variant"),
|
|
1330
|
-
slideType:
|
|
1331
|
-
content: z15.record(z15.unknown()).optional().describe('Type-specific content object. For bullets: {title, items: ["..."]}. For title: {title, subtitle}. For
|
|
1357
|
+
slideType: z15.enum(SLIDE_TYPES).default("bullets").describe("The type of slide to create: title, section_header, bullets, image, code, mermaid, paragraph"),
|
|
1358
|
+
content: z15.record(z15.unknown()).optional().describe('Type-specific content object. For bullets: {title, items: ["..."]}. For title: {title, subtitle}. For image: {title, imageUrl, caption}. For code: {title, code, language}. For mermaid: {title, code: "graph TD; A-->B"}. For paragraph: {title, body}. For section_header: {title, subtitle}.'),
|
|
1332
1359
|
speakerNotes: z15.string().nullable().optional().describe("Speaker notes for the slide")
|
|
1333
1360
|
};
|
|
1334
1361
|
var updateSlideInput = {
|
|
@@ -1425,6 +1452,10 @@ class ApiClient {
|
|
|
1425
1452
|
searchParams.set("horizon", params.horizon);
|
|
1426
1453
|
if (params?.query)
|
|
1427
1454
|
searchParams.set("query", params.query);
|
|
1455
|
+
if (params?.phase)
|
|
1456
|
+
searchParams.set("phase", params.phase);
|
|
1457
|
+
if (params?.phaseStep)
|
|
1458
|
+
searchParams.set("phaseStep", params.phaseStep);
|
|
1428
1459
|
const queryString = searchParams.toString();
|
|
1429
1460
|
const path = queryString ? `/v1/roadmaps?${queryString}` : "/v1/roadmaps";
|
|
1430
1461
|
return await this.request(path);
|
|
@@ -2048,6 +2079,39 @@ class ApiClient {
|
|
|
2048
2079
|
});
|
|
2049
2080
|
return response.data;
|
|
2050
2081
|
}
|
|
2082
|
+
async createPresentationFeedbackSession(presentationId, variantId, data) {
|
|
2083
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`, {
|
|
2084
|
+
method: "POST",
|
|
2085
|
+
body: JSON.stringify(data)
|
|
2086
|
+
});
|
|
2087
|
+
return response.data;
|
|
2088
|
+
}
|
|
2089
|
+
async listPresentationFeedbackSessions(presentationId, variantId) {
|
|
2090
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`);
|
|
2091
|
+
return response.data;
|
|
2092
|
+
}
|
|
2093
|
+
async getPresentationFeedback(presentationId, variantId, sessionId) {
|
|
2094
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback`);
|
|
2095
|
+
return response.data;
|
|
2096
|
+
}
|
|
2097
|
+
async getPresentationFeedbackStats(presentationId, variantId, sessionId) {
|
|
2098
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/stats`);
|
|
2099
|
+
return response.data;
|
|
2100
|
+
}
|
|
2101
|
+
async resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, data) {
|
|
2102
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback/${feedbackId}/resolve`, {
|
|
2103
|
+
method: "PATCH",
|
|
2104
|
+
body: JSON.stringify(data)
|
|
2105
|
+
});
|
|
2106
|
+
return response.data;
|
|
2107
|
+
}
|
|
2108
|
+
async addPresentationReviewer(presentationId, variantId, sessionId, data) {
|
|
2109
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/invites`, {
|
|
2110
|
+
method: "POST",
|
|
2111
|
+
body: JSON.stringify(data)
|
|
2112
|
+
});
|
|
2113
|
+
return response.data;
|
|
2114
|
+
}
|
|
2051
2115
|
async getVariantPresentationId(variantId) {
|
|
2052
2116
|
const presentations = await this.listPresentations();
|
|
2053
2117
|
for (const presentation2 of presentations.items) {
|
|
@@ -2175,6 +2239,12 @@ function registerAllTools(server) {
|
|
|
2175
2239
|
registerDeleteSlide(server);
|
|
2176
2240
|
registerReorderSlides(server);
|
|
2177
2241
|
registerUploadSlideImage(server);
|
|
2242
|
+
registerCreatePresentationFeedbackSession(server);
|
|
2243
|
+
registerListPresentationFeedbackSessions(server);
|
|
2244
|
+
registerGetPresentationFeedbackSummary(server);
|
|
2245
|
+
registerGetPresentationFeedbackDetail(server);
|
|
2246
|
+
registerResolvePresentationFeedback(server);
|
|
2247
|
+
registerAddPresentationReviewer(server);
|
|
2178
2248
|
}
|
|
2179
2249
|
function registerGetWorkflows(server) {
|
|
2180
2250
|
server.registerTool("get_workflows", {
|
|
@@ -2437,11 +2507,9 @@ Use this as your FIRST call when starting work on a roadmap to understand the fu
|
|
|
2437
2507
|
})),
|
|
2438
2508
|
audiences: audiences.map((a) => ({
|
|
2439
2509
|
id: a.id,
|
|
2510
|
+
name: a.name,
|
|
2440
2511
|
type: a.type,
|
|
2441
|
-
|
|
2442
|
-
likes: a.likes,
|
|
2443
|
-
dislikes: a.dislikes,
|
|
2444
|
-
priorities: a.priorities
|
|
2512
|
+
description: a.description
|
|
2445
2513
|
})),
|
|
2446
2514
|
scenarios: scenarios.map((s) => ({
|
|
2447
2515
|
id: s.id,
|
|
@@ -4789,7 +4857,7 @@ function registerGetSlide(server) {
|
|
|
4789
4857
|
}
|
|
4790
4858
|
function registerCreateSlide(server) {
|
|
4791
4859
|
server.registerTool("create_slide", {
|
|
4792
|
-
description: "Create a new slide in a variant. Slide types: title (title + subtitle), section_header (title + subtitle), bullets (title + items array),
|
|
4860
|
+
description: "Create a new slide in a variant. Slide types: title (title + subtitle), section_header (title + subtitle), bullets (title + items array), image (title + imageUrl + caption), code (title + code + language), mermaid (title + code with mermaid diagram syntax), paragraph (title + body with markdown text).",
|
|
4793
4861
|
inputSchema: createSlideInput
|
|
4794
4862
|
}, async ({
|
|
4795
4863
|
variantId,
|
|
@@ -5016,7 +5084,9 @@ function registerCreateFeedbackSession(server) {
|
|
|
5016
5084
|
const invite = session.invites[0];
|
|
5017
5085
|
if (!invite) {
|
|
5018
5086
|
return {
|
|
5019
|
-
content: [
|
|
5087
|
+
content: [
|
|
5088
|
+
{ type: "text", text: "Error: No invite was created for the session." }
|
|
5089
|
+
]
|
|
5020
5090
|
};
|
|
5021
5091
|
}
|
|
5022
5092
|
const reviewUrl = `https://app.ourroadmaps.com/prototype-review/${invite.token}`;
|
|
@@ -5201,6 +5271,253 @@ function registerResolveFeedbackComment(server) {
|
|
|
5201
5271
|
};
|
|
5202
5272
|
});
|
|
5203
5273
|
}
|
|
5274
|
+
function registerCreatePresentationFeedbackSession(server) {
|
|
5275
|
+
server.registerTool("create_presentation_feedback_session", {
|
|
5276
|
+
description: "Create a feedback session for a presentation variant and get a shareable review link. Reviewers can leave per-slide comments and emoji reactions.",
|
|
5277
|
+
inputSchema: createPresentationFeedbackSessionInput
|
|
5278
|
+
}, async ({
|
|
5279
|
+
presentationId,
|
|
5280
|
+
variantId,
|
|
5281
|
+
message,
|
|
5282
|
+
expiresInDays
|
|
5283
|
+
}) => {
|
|
5284
|
+
const client2 = getApiClient();
|
|
5285
|
+
const session = await client2.createPresentationFeedbackSession(presentationId, variantId, {
|
|
5286
|
+
message,
|
|
5287
|
+
reviewerVisibility: true,
|
|
5288
|
+
expiresInDays,
|
|
5289
|
+
reviewers: [{ name: "Anonymous" }]
|
|
5290
|
+
});
|
|
5291
|
+
const invite = session.invites[0];
|
|
5292
|
+
if (!invite) {
|
|
5293
|
+
return {
|
|
5294
|
+
content: [
|
|
5295
|
+
{ type: "text", text: "Error: No invite was created for the session." }
|
|
5296
|
+
]
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
|
|
5300
|
+
const expiryDate = new Date(session.expiresAt).toLocaleDateString("en-US", {
|
|
5301
|
+
weekday: "long",
|
|
5302
|
+
year: "numeric",
|
|
5303
|
+
month: "long",
|
|
5304
|
+
day: "numeric"
|
|
5305
|
+
});
|
|
5306
|
+
return {
|
|
5307
|
+
content: [
|
|
5308
|
+
{
|
|
5309
|
+
type: "text",
|
|
5310
|
+
text: JSON.stringify({
|
|
5311
|
+
success: true,
|
|
5312
|
+
sessionId: session.id,
|
|
5313
|
+
sessionName: session.name,
|
|
5314
|
+
reviewUrl,
|
|
5315
|
+
expiresAt: session.expiresAt,
|
|
5316
|
+
expiryDate
|
|
5317
|
+
}, null, 2)
|
|
5318
|
+
}
|
|
5319
|
+
]
|
|
5320
|
+
};
|
|
5321
|
+
});
|
|
5322
|
+
}
|
|
5323
|
+
function registerListPresentationFeedbackSessions(server) {
|
|
5324
|
+
server.registerTool("list_presentation_feedback_sessions", {
|
|
5325
|
+
description: "List all feedback sessions for a presentation variant with invite counts and status.",
|
|
5326
|
+
inputSchema: listPresentationFeedbackSessionsInput
|
|
5327
|
+
}, async ({ presentationId, variantId }) => {
|
|
5328
|
+
const client2 = getApiClient();
|
|
5329
|
+
const sessions = await client2.listPresentationFeedbackSessions(presentationId, variantId);
|
|
5330
|
+
return {
|
|
5331
|
+
content: [
|
|
5332
|
+
{
|
|
5333
|
+
type: "text",
|
|
5334
|
+
text: JSON.stringify({
|
|
5335
|
+
sessions: sessions.map((s) => ({
|
|
5336
|
+
id: s.id,
|
|
5337
|
+
name: s.name,
|
|
5338
|
+
status: s.status,
|
|
5339
|
+
inviteCount: s.invites.length,
|
|
5340
|
+
expiresAt: s.expiresAt,
|
|
5341
|
+
createdAt: s.createdAt
|
|
5342
|
+
}))
|
|
5343
|
+
}, null, 2)
|
|
5344
|
+
}
|
|
5345
|
+
]
|
|
5346
|
+
};
|
|
5347
|
+
});
|
|
5348
|
+
}
|
|
5349
|
+
function registerGetPresentationFeedbackSummary(server) {
|
|
5350
|
+
server.registerTool("get_presentation_feedback_summary", {
|
|
5351
|
+
description: "Get a human-readable summary of presentation feedback, grouped by slide. Shows reviewer names, comments, emoji reactions, and resolved status. Use this for a quick overview.",
|
|
5352
|
+
inputSchema: getPresentationFeedbackSummaryInput
|
|
5353
|
+
}, async ({
|
|
5354
|
+
presentationId,
|
|
5355
|
+
variantId,
|
|
5356
|
+
sessionId,
|
|
5357
|
+
filter
|
|
5358
|
+
}) => {
|
|
5359
|
+
const client2 = getApiClient();
|
|
5360
|
+
const [stats, feedback] = await Promise.all([
|
|
5361
|
+
client2.getPresentationFeedbackStats(presentationId, variantId, sessionId),
|
|
5362
|
+
client2.getPresentationFeedback(presentationId, variantId, sessionId)
|
|
5363
|
+
]);
|
|
5364
|
+
const resolvedFilter = filter ?? "unresolved";
|
|
5365
|
+
const filtered = resolvedFilter === "all" ? feedback : feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
|
|
5366
|
+
if (filtered.length === 0) {
|
|
5367
|
+
return {
|
|
5368
|
+
content: [{ type: "text", text: "No feedback found matching the filter." }]
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
const slideFeedback = filtered.filter((f) => f.type === "slide");
|
|
5372
|
+
const overallFeedback = filtered.filter((f) => f.type === "overall");
|
|
5373
|
+
const bySlide = new Map;
|
|
5374
|
+
for (const f of slideFeedback) {
|
|
5375
|
+
const key = f.slideId ?? "(unknown)";
|
|
5376
|
+
if (!bySlide.has(key))
|
|
5377
|
+
bySlide.set(key, []);
|
|
5378
|
+
bySlide.get(key).push(f);
|
|
5379
|
+
}
|
|
5380
|
+
let summary = `## Session (${stats.respondedCount}/${stats.totalInvites} responded, ${stats.unresolvedCount} unresolved)
|
|
5381
|
+
|
|
5382
|
+
`;
|
|
5383
|
+
const sortedSlides = [...bySlide.entries()].sort((a, b) => {
|
|
5384
|
+
const orderA = a[1][0]?.slideOrder ?? 0;
|
|
5385
|
+
const orderB = b[1][0]?.slideOrder ?? 0;
|
|
5386
|
+
return orderA - orderB;
|
|
5387
|
+
});
|
|
5388
|
+
for (const [, comments] of sortedSlides) {
|
|
5389
|
+
const first = comments[0];
|
|
5390
|
+
summary += `### Slide ${(first.slideOrder ?? 0) + 1}: "${first.slideTitle ?? "Untitled"}"
|
|
5391
|
+
`;
|
|
5392
|
+
for (const c of comments) {
|
|
5393
|
+
const status = c.resolved ? "RESOLVED" : "OPEN";
|
|
5394
|
+
summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
|
|
5395
|
+
`;
|
|
5396
|
+
if (c.emojiReactions && c.emojiReactions.length > 0) {
|
|
5397
|
+
summary += ` Reactions: ${c.emojiReactions.join(", ")}
|
|
5398
|
+
`;
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
summary += `
|
|
5402
|
+
`;
|
|
5403
|
+
}
|
|
5404
|
+
if (overallFeedback.length > 0) {
|
|
5405
|
+
summary += `### Overall Feedback
|
|
5406
|
+
`;
|
|
5407
|
+
for (const c of overallFeedback) {
|
|
5408
|
+
const status = c.resolved ? "RESOLVED" : "OPEN";
|
|
5409
|
+
summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
|
|
5410
|
+
`;
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
return {
|
|
5414
|
+
content: [{ type: "text", text: summary.trim() }]
|
|
5415
|
+
};
|
|
5416
|
+
});
|
|
5417
|
+
}
|
|
5418
|
+
function registerGetPresentationFeedbackDetail(server) {
|
|
5419
|
+
server.registerTool("get_presentation_feedback_detail", {
|
|
5420
|
+
description: "Get full raw feedback data for a presentation session, including slide IDs, emoji reactions, and resolved status. Use this when you need exact data to make targeted slide updates.",
|
|
5421
|
+
inputSchema: getPresentationFeedbackDetailInput
|
|
5422
|
+
}, async ({
|
|
5423
|
+
presentationId,
|
|
5424
|
+
variantId,
|
|
5425
|
+
sessionId,
|
|
5426
|
+
feedbackId,
|
|
5427
|
+
filter
|
|
5428
|
+
}) => {
|
|
5429
|
+
const client2 = getApiClient();
|
|
5430
|
+
const feedback = await client2.getPresentationFeedback(presentationId, variantId, sessionId);
|
|
5431
|
+
let filtered = feedback;
|
|
5432
|
+
if (feedbackId) {
|
|
5433
|
+
filtered = feedback.filter((f) => f.id === feedbackId);
|
|
5434
|
+
if (filtered.length === 0) {
|
|
5435
|
+
return {
|
|
5436
|
+
content: [
|
|
5437
|
+
{
|
|
5438
|
+
type: "text",
|
|
5439
|
+
text: `Feedback item ${feedbackId} not found in this session.`
|
|
5440
|
+
}
|
|
5441
|
+
]
|
|
5442
|
+
};
|
|
5443
|
+
}
|
|
5444
|
+
} else {
|
|
5445
|
+
const resolvedFilter = filter ?? "all";
|
|
5446
|
+
if (resolvedFilter !== "all") {
|
|
5447
|
+
filtered = feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
return {
|
|
5451
|
+
content: [
|
|
5452
|
+
{
|
|
5453
|
+
type: "text",
|
|
5454
|
+
text: JSON.stringify({ feedback: filtered }, null, 2)
|
|
5455
|
+
}
|
|
5456
|
+
]
|
|
5457
|
+
};
|
|
5458
|
+
});
|
|
5459
|
+
}
|
|
5460
|
+
function registerResolvePresentationFeedback(server) {
|
|
5461
|
+
server.registerTool("resolve_presentation_feedback", {
|
|
5462
|
+
description: "Set the resolved status on a presentation feedback item. Requires the feedback type (slide or overall) and the desired resolved state.",
|
|
5463
|
+
inputSchema: resolvePresentationFeedbackInput
|
|
5464
|
+
}, async ({
|
|
5465
|
+
presentationId,
|
|
5466
|
+
variantId,
|
|
5467
|
+
sessionId,
|
|
5468
|
+
feedbackId,
|
|
5469
|
+
type,
|
|
5470
|
+
resolved
|
|
5471
|
+
}) => {
|
|
5472
|
+
const client2 = getApiClient();
|
|
5473
|
+
const result = await client2.resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, { type, resolved });
|
|
5474
|
+
return {
|
|
5475
|
+
content: [
|
|
5476
|
+
{
|
|
5477
|
+
type: "text",
|
|
5478
|
+
text: JSON.stringify({
|
|
5479
|
+
success: true,
|
|
5480
|
+
feedbackId: result.id,
|
|
5481
|
+
resolved: result.resolved
|
|
5482
|
+
}, null, 2)
|
|
5483
|
+
}
|
|
5484
|
+
]
|
|
5485
|
+
};
|
|
5486
|
+
});
|
|
5487
|
+
}
|
|
5488
|
+
function registerAddPresentationReviewer(server) {
|
|
5489
|
+
server.registerTool("add_presentation_reviewer", {
|
|
5490
|
+
description: "Add a reviewer to an active presentation feedback session. Returns a unique review URL for the new reviewer.",
|
|
5491
|
+
inputSchema: addPresentationReviewerInput
|
|
5492
|
+
}, async ({
|
|
5493
|
+
presentationId,
|
|
5494
|
+
variantId,
|
|
5495
|
+
sessionId,
|
|
5496
|
+
name,
|
|
5497
|
+
email
|
|
5498
|
+
}) => {
|
|
5499
|
+
const client2 = getApiClient();
|
|
5500
|
+
const invite = await client2.addPresentationReviewer(presentationId, variantId, sessionId, {
|
|
5501
|
+
name,
|
|
5502
|
+
email
|
|
5503
|
+
});
|
|
5504
|
+
const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
|
|
5505
|
+
return {
|
|
5506
|
+
content: [
|
|
5507
|
+
{
|
|
5508
|
+
type: "text",
|
|
5509
|
+
text: JSON.stringify({
|
|
5510
|
+
success: true,
|
|
5511
|
+
inviteId: invite.id,
|
|
5512
|
+
reviewUrl,
|
|
5513
|
+
reviewerName: invite.reviewerName,
|
|
5514
|
+
reviewerEmail: invite.reviewerEmail
|
|
5515
|
+
}, null, 2)
|
|
5516
|
+
}
|
|
5517
|
+
]
|
|
5518
|
+
};
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5204
5521
|
|
|
5205
5522
|
// src/index.ts
|
|
5206
5523
|
async function main() {
|