@ourroadmaps/mcp 0.30.1 → 0.32.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 +497 -55
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -776,13 +776,8 @@ var SLIDE_TYPES = [
|
|
|
776
776
|
"title",
|
|
777
777
|
"section_header",
|
|
778
778
|
"bullets",
|
|
779
|
-
"two_column",
|
|
780
|
-
"comparison",
|
|
781
|
-
"timeline",
|
|
782
779
|
"image",
|
|
783
|
-
"quote",
|
|
784
780
|
"code",
|
|
785
|
-
"thank_you",
|
|
786
781
|
"mermaid",
|
|
787
782
|
"paragraph"
|
|
788
783
|
];
|
|
@@ -799,46 +794,17 @@ var bulletsContentSchema = z13.object({
|
|
|
799
794
|
title: z13.string().optional(),
|
|
800
795
|
items: z13.array(z13.string()).default([])
|
|
801
796
|
});
|
|
802
|
-
var twoColumnContentSchema = z13.object({
|
|
803
|
-
title: z13.string().optional(),
|
|
804
|
-
left: z13.string().default(""),
|
|
805
|
-
right: z13.string().default("")
|
|
806
|
-
});
|
|
807
|
-
var comparisonContentSchema = z13.object({
|
|
808
|
-
leftLabel: z13.string().default(""),
|
|
809
|
-
leftContent: z13.string().default(""),
|
|
810
|
-
rightLabel: z13.string().default(""),
|
|
811
|
-
rightContent: z13.string().default("")
|
|
812
|
-
});
|
|
813
|
-
var timelineStepSchema = z13.object({
|
|
814
|
-
title: z13.string(),
|
|
815
|
-
description: z13.string().optional()
|
|
816
|
-
});
|
|
817
|
-
var timelineContentSchema = z13.object({
|
|
818
|
-
title: z13.string().optional(),
|
|
819
|
-
steps: z13.array(timelineStepSchema).default([])
|
|
820
|
-
});
|
|
821
797
|
var imageContentSchema = z13.object({
|
|
822
798
|
title: z13.string().optional(),
|
|
823
799
|
imageUrl: z13.string().optional(),
|
|
824
800
|
caption: z13.string().optional()
|
|
825
801
|
});
|
|
826
|
-
var quoteContentSchema = z13.object({
|
|
827
|
-
quote: z13.string().default(""),
|
|
828
|
-
attribution: z13.string().optional()
|
|
829
|
-
});
|
|
830
802
|
var codeContentSchema = z13.object({
|
|
831
803
|
title: z13.string().optional(),
|
|
832
804
|
code: z13.string().default(""),
|
|
833
805
|
language: z13.string().optional(),
|
|
834
806
|
highlightLines: z13.array(z13.number()).optional()
|
|
835
807
|
});
|
|
836
|
-
var thankYouContentSchema = z13.object({
|
|
837
|
-
title: z13.string().default("Thank You"),
|
|
838
|
-
subtitle: z13.string().optional(),
|
|
839
|
-
ctaText: z13.string().optional(),
|
|
840
|
-
ctaUrl: z13.string().optional()
|
|
841
|
-
});
|
|
842
808
|
var mermaidContentSchema = z13.object({
|
|
843
809
|
title: z13.string().optional(),
|
|
844
810
|
code: z13.string().default("")
|
|
@@ -851,13 +817,8 @@ var typedSlideContentSchema = z13.discriminatedUnion("type", [
|
|
|
851
817
|
z13.object({ type: z13.literal("title"), ...titleContentSchema.shape }),
|
|
852
818
|
z13.object({ type: z13.literal("section_header"), ...sectionHeaderContentSchema.shape }),
|
|
853
819
|
z13.object({ type: z13.literal("bullets"), ...bulletsContentSchema.shape }),
|
|
854
|
-
z13.object({ type: z13.literal("two_column"), ...twoColumnContentSchema.shape }),
|
|
855
|
-
z13.object({ type: z13.literal("comparison"), ...comparisonContentSchema.shape }),
|
|
856
|
-
z13.object({ type: z13.literal("timeline"), ...timelineContentSchema.shape }),
|
|
857
820
|
z13.object({ type: z13.literal("image"), ...imageContentSchema.shape }),
|
|
858
|
-
z13.object({ type: z13.literal("quote"), ...quoteContentSchema.shape }),
|
|
859
821
|
z13.object({ type: z13.literal("code"), ...codeContentSchema.shape }),
|
|
860
|
-
z13.object({ type: z13.literal("thank_you"), ...thankYouContentSchema.shape }),
|
|
861
822
|
z13.object({ type: z13.literal("mermaid"), ...mermaidContentSchema.shape }),
|
|
862
823
|
z13.object({ type: z13.literal("paragraph"), ...paragraphContentSchema.shape })
|
|
863
824
|
]);
|
|
@@ -983,6 +944,18 @@ var updateBrainstormNotesInput = {
|
|
|
983
944
|
roadmapId: idField("roadmap item"),
|
|
984
945
|
notes: z15.string().describe("The brainstorm notes content")
|
|
985
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
|
+
};
|
|
986
959
|
var searchFeaturesInput = {
|
|
987
960
|
query: z15.string().optional().describe("Search query to match against name"),
|
|
988
961
|
type: featureTypeSchema.optional().describe("Filter by type (feature or area)")
|
|
@@ -1089,16 +1062,7 @@ var deleteAudienceInput = {
|
|
|
1089
1062
|
var getHistoryInput = {
|
|
1090
1063
|
startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
|
|
1091
1064
|
endDate: yyyyMmDdField("End date in YYYY-MM-DD format"),
|
|
1092
|
-
entityType: z15.enum([
|
|
1093
|
-
"roadmap",
|
|
1094
|
-
"feature",
|
|
1095
|
-
"idea",
|
|
1096
|
-
"prd",
|
|
1097
|
-
"wireframe",
|
|
1098
|
-
"product",
|
|
1099
|
-
"audience",
|
|
1100
|
-
"scenario"
|
|
1101
|
-
]).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")
|
|
1102
1066
|
};
|
|
1103
1067
|
var getHistorySummaryInput = {
|
|
1104
1068
|
startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
|
|
@@ -1143,7 +1107,18 @@ var createInitiativeInput = {
|
|
|
1143
1107
|
horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")'),
|
|
1144
1108
|
dateGranularity: dateGranularitySchema.optional().describe("Target date granularity: day, month, quarter, half-year, or year"),
|
|
1145
1109
|
dateValue: z15.string().optional().describe('Target date value matching granularity (e.g., "2024-Q1", "2024-03")'),
|
|
1146
|
-
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")
|
|
1147
1122
|
};
|
|
1148
1123
|
var updateInitiativeInput = {
|
|
1149
1124
|
id: idField("initiative to update"),
|
|
@@ -1153,7 +1128,18 @@ var updateInitiativeInput = {
|
|
|
1153
1128
|
dateGranularity: dateGranularitySchema.nullable().optional().describe("New target date granularity (null to clear)"),
|
|
1154
1129
|
dateValue: z15.string().nullable().optional().describe("New target date value (null to clear)"),
|
|
1155
1130
|
targetDate: z15.string().nullable().optional().describe("New target date in YYYY-MM-DD format (null to clear)"),
|
|
1156
|
-
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)")
|
|
1157
1143
|
};
|
|
1158
1144
|
var deleteInitiativeInput = {
|
|
1159
1145
|
id: idField("initiative to delete")
|
|
@@ -1241,6 +1227,44 @@ var resolveFeedbackCommentInput = {
|
|
|
1241
1227
|
sessionId: uuidField("feedback session"),
|
|
1242
1228
|
commentId: uuidField("comment to resolve/unresolve")
|
|
1243
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
|
+
};
|
|
1244
1268
|
var searchExportsInput = {
|
|
1245
1269
|
roadmapId: z15.string().uuid().optional().describe("Filter by roadmap item ID"),
|
|
1246
1270
|
externalSystem: externalSystemSchema.optional().describe("Filter by external system"),
|
|
@@ -1330,8 +1354,8 @@ var getSlideInput = {
|
|
|
1330
1354
|
};
|
|
1331
1355
|
var createSlideInput = {
|
|
1332
1356
|
variantId: idField("variant"),
|
|
1333
|
-
slideType:
|
|
1334
|
-
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}.'),
|
|
1335
1359
|
speakerNotes: z15.string().nullable().optional().describe("Speaker notes for the slide")
|
|
1336
1360
|
};
|
|
1337
1361
|
var updateSlideInput = {
|
|
@@ -1354,6 +1378,33 @@ var uploadSlideImageInput = {
|
|
|
1354
1378
|
slideId: idField("slide to add the image to"),
|
|
1355
1379
|
filePath: z15.string().describe("Absolute path to the image file on disk")
|
|
1356
1380
|
};
|
|
1381
|
+
var listVerificationRunsInput = {
|
|
1382
|
+
roadmapId: idField("roadmap item")
|
|
1383
|
+
};
|
|
1384
|
+
var getVerificationRunInput = {
|
|
1385
|
+
roadmapId: idField("roadmap item"),
|
|
1386
|
+
runId: idField("verification run")
|
|
1387
|
+
};
|
|
1388
|
+
var createVerificationRunInput = {
|
|
1389
|
+
roadmapId: idField("roadmap item"),
|
|
1390
|
+
appUrl: z15.string().describe("URL where the running app is accessible"),
|
|
1391
|
+
verificationTypes: z15.array(z15.enum(["outcomes", "visual", "edge-cases"])).optional().describe("Types of verification to include (defaults to all)"),
|
|
1392
|
+
totalOutcomes: z15.number().int().describe("Total number of PRD outcomes being checked")
|
|
1393
|
+
};
|
|
1394
|
+
var updateVerificationRunInput = {
|
|
1395
|
+
roadmapId: idField("roadmap item"),
|
|
1396
|
+
runId: idField("verification run"),
|
|
1397
|
+
status: z15.enum(["running", "completed", "partial", "failed"]).optional(),
|
|
1398
|
+
passedOutcomes: z15.number().int().optional(),
|
|
1399
|
+
failedOutcomes: z15.number().int().optional(),
|
|
1400
|
+
skippedOutcomes: z15.number().int().optional(),
|
|
1401
|
+
outcomeResults: z15.string().optional().describe("JSON string of outcome check results"),
|
|
1402
|
+
visualResults: z15.string().optional().describe("JSON string of visual comparison results"),
|
|
1403
|
+
edgeCaseResults: z15.string().optional().describe("JSON string of edge case results"),
|
|
1404
|
+
fixPrompt: z15.string().optional().describe("Generated fix prompt text"),
|
|
1405
|
+
durationMs: z15.number().int().optional(),
|
|
1406
|
+
completedAt: z15.string().datetime().optional().describe("ISO timestamp when the run completed")
|
|
1407
|
+
};
|
|
1357
1408
|
// ../../packages/shared/src/schemas/variant.ts
|
|
1358
1409
|
import { z as z16 } from "zod";
|
|
1359
1410
|
var variantSchema = z16.object({
|
|
@@ -2055,6 +2106,57 @@ class ApiClient {
|
|
|
2055
2106
|
});
|
|
2056
2107
|
return response.data;
|
|
2057
2108
|
}
|
|
2109
|
+
async createPresentationFeedbackSession(presentationId, variantId, data) {
|
|
2110
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`, {
|
|
2111
|
+
method: "POST",
|
|
2112
|
+
body: JSON.stringify(data)
|
|
2113
|
+
});
|
|
2114
|
+
return response.data;
|
|
2115
|
+
}
|
|
2116
|
+
async listPresentationFeedbackSessions(presentationId, variantId) {
|
|
2117
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`);
|
|
2118
|
+
return response.data;
|
|
2119
|
+
}
|
|
2120
|
+
async getPresentationFeedback(presentationId, variantId, sessionId) {
|
|
2121
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback`);
|
|
2122
|
+
return response.data;
|
|
2123
|
+
}
|
|
2124
|
+
async getPresentationFeedbackStats(presentationId, variantId, sessionId) {
|
|
2125
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/stats`);
|
|
2126
|
+
return response.data;
|
|
2127
|
+
}
|
|
2128
|
+
async resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, data) {
|
|
2129
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback/${feedbackId}/resolve`, {
|
|
2130
|
+
method: "PATCH",
|
|
2131
|
+
body: JSON.stringify(data)
|
|
2132
|
+
});
|
|
2133
|
+
return response.data;
|
|
2134
|
+
}
|
|
2135
|
+
async addPresentationReviewer(presentationId, variantId, sessionId, data) {
|
|
2136
|
+
const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/invites`, {
|
|
2137
|
+
method: "POST",
|
|
2138
|
+
body: JSON.stringify(data)
|
|
2139
|
+
});
|
|
2140
|
+
return response.data;
|
|
2141
|
+
}
|
|
2142
|
+
async listVerificationRuns(roadmapId) {
|
|
2143
|
+
return this.request(`/v1/roadmaps/${roadmapId}/verification-runs`);
|
|
2144
|
+
}
|
|
2145
|
+
async getVerificationRun(roadmapId, runId) {
|
|
2146
|
+
return this.request(`/v1/roadmaps/${roadmapId}/verification-runs/${runId}`);
|
|
2147
|
+
}
|
|
2148
|
+
async createVerificationRun(roadmapId, body) {
|
|
2149
|
+
return this.request(`/v1/roadmaps/${roadmapId}/verification-runs`, {
|
|
2150
|
+
method: "POST",
|
|
2151
|
+
body: JSON.stringify(body)
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
async updateVerificationRun(roadmapId, runId, body) {
|
|
2155
|
+
return this.request(`/v1/roadmaps/${roadmapId}/verification-runs/${runId}`, {
|
|
2156
|
+
method: "PATCH",
|
|
2157
|
+
body: JSON.stringify(body)
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2058
2160
|
async getVariantPresentationId(variantId) {
|
|
2059
2161
|
const presentations = await this.listPresentations();
|
|
2060
2162
|
for (const presentation2 of presentations.items) {
|
|
@@ -2182,6 +2284,16 @@ function registerAllTools(server) {
|
|
|
2182
2284
|
registerDeleteSlide(server);
|
|
2183
2285
|
registerReorderSlides(server);
|
|
2184
2286
|
registerUploadSlideImage(server);
|
|
2287
|
+
registerCreatePresentationFeedbackSession(server);
|
|
2288
|
+
registerListPresentationFeedbackSessions(server);
|
|
2289
|
+
registerGetPresentationFeedbackSummary(server);
|
|
2290
|
+
registerGetPresentationFeedbackDetail(server);
|
|
2291
|
+
registerResolvePresentationFeedback(server);
|
|
2292
|
+
registerAddPresentationReviewer(server);
|
|
2293
|
+
registerListVerificationRuns(server);
|
|
2294
|
+
registerGetVerificationRun(server);
|
|
2295
|
+
registerCreateVerificationRun(server);
|
|
2296
|
+
registerUpdateVerificationRun(server);
|
|
2185
2297
|
}
|
|
2186
2298
|
function registerGetWorkflows(server) {
|
|
2187
2299
|
server.registerTool("get_workflows", {
|
|
@@ -4794,7 +4906,7 @@ function registerGetSlide(server) {
|
|
|
4794
4906
|
}
|
|
4795
4907
|
function registerCreateSlide(server) {
|
|
4796
4908
|
server.registerTool("create_slide", {
|
|
4797
|
-
description: "Create a new slide in a variant. Slide types: title (title + subtitle), section_header (title + subtitle), bullets (title + items array),
|
|
4909
|
+
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).",
|
|
4798
4910
|
inputSchema: createSlideInput
|
|
4799
4911
|
}, async ({
|
|
4800
4912
|
variantId,
|
|
@@ -5021,7 +5133,9 @@ function registerCreateFeedbackSession(server) {
|
|
|
5021
5133
|
const invite = session.invites[0];
|
|
5022
5134
|
if (!invite) {
|
|
5023
5135
|
return {
|
|
5024
|
-
content: [
|
|
5136
|
+
content: [
|
|
5137
|
+
{ type: "text", text: "Error: No invite was created for the session." }
|
|
5138
|
+
]
|
|
5025
5139
|
};
|
|
5026
5140
|
}
|
|
5027
5141
|
const reviewUrl = `https://app.ourroadmaps.com/prototype-review/${invite.token}`;
|
|
@@ -5206,6 +5320,334 @@ function registerResolveFeedbackComment(server) {
|
|
|
5206
5320
|
};
|
|
5207
5321
|
});
|
|
5208
5322
|
}
|
|
5323
|
+
function registerCreatePresentationFeedbackSession(server) {
|
|
5324
|
+
server.registerTool("create_presentation_feedback_session", {
|
|
5325
|
+
description: "Create a feedback session for a presentation variant and get a shareable review link. Reviewers can leave per-slide comments and emoji reactions.",
|
|
5326
|
+
inputSchema: createPresentationFeedbackSessionInput
|
|
5327
|
+
}, async ({
|
|
5328
|
+
presentationId,
|
|
5329
|
+
variantId,
|
|
5330
|
+
message,
|
|
5331
|
+
expiresInDays
|
|
5332
|
+
}) => {
|
|
5333
|
+
const client2 = getApiClient();
|
|
5334
|
+
const session = await client2.createPresentationFeedbackSession(presentationId, variantId, {
|
|
5335
|
+
message,
|
|
5336
|
+
reviewerVisibility: true,
|
|
5337
|
+
expiresInDays,
|
|
5338
|
+
reviewers: [{ name: "Anonymous" }]
|
|
5339
|
+
});
|
|
5340
|
+
const invite = session.invites[0];
|
|
5341
|
+
if (!invite) {
|
|
5342
|
+
return {
|
|
5343
|
+
content: [
|
|
5344
|
+
{ type: "text", text: "Error: No invite was created for the session." }
|
|
5345
|
+
]
|
|
5346
|
+
};
|
|
5347
|
+
}
|
|
5348
|
+
const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
|
|
5349
|
+
const expiryDate = new Date(session.expiresAt).toLocaleDateString("en-US", {
|
|
5350
|
+
weekday: "long",
|
|
5351
|
+
year: "numeric",
|
|
5352
|
+
month: "long",
|
|
5353
|
+
day: "numeric"
|
|
5354
|
+
});
|
|
5355
|
+
return {
|
|
5356
|
+
content: [
|
|
5357
|
+
{
|
|
5358
|
+
type: "text",
|
|
5359
|
+
text: JSON.stringify({
|
|
5360
|
+
success: true,
|
|
5361
|
+
sessionId: session.id,
|
|
5362
|
+
sessionName: session.name,
|
|
5363
|
+
reviewUrl,
|
|
5364
|
+
expiresAt: session.expiresAt,
|
|
5365
|
+
expiryDate
|
|
5366
|
+
}, null, 2)
|
|
5367
|
+
}
|
|
5368
|
+
]
|
|
5369
|
+
};
|
|
5370
|
+
});
|
|
5371
|
+
}
|
|
5372
|
+
function registerListPresentationFeedbackSessions(server) {
|
|
5373
|
+
server.registerTool("list_presentation_feedback_sessions", {
|
|
5374
|
+
description: "List all feedback sessions for a presentation variant with invite counts and status.",
|
|
5375
|
+
inputSchema: listPresentationFeedbackSessionsInput
|
|
5376
|
+
}, async ({ presentationId, variantId }) => {
|
|
5377
|
+
const client2 = getApiClient();
|
|
5378
|
+
const sessions = await client2.listPresentationFeedbackSessions(presentationId, variantId);
|
|
5379
|
+
return {
|
|
5380
|
+
content: [
|
|
5381
|
+
{
|
|
5382
|
+
type: "text",
|
|
5383
|
+
text: JSON.stringify({
|
|
5384
|
+
sessions: sessions.map((s) => ({
|
|
5385
|
+
id: s.id,
|
|
5386
|
+
name: s.name,
|
|
5387
|
+
status: s.status,
|
|
5388
|
+
inviteCount: s.invites.length,
|
|
5389
|
+
expiresAt: s.expiresAt,
|
|
5390
|
+
createdAt: s.createdAt
|
|
5391
|
+
}))
|
|
5392
|
+
}, null, 2)
|
|
5393
|
+
}
|
|
5394
|
+
]
|
|
5395
|
+
};
|
|
5396
|
+
});
|
|
5397
|
+
}
|
|
5398
|
+
function registerGetPresentationFeedbackSummary(server) {
|
|
5399
|
+
server.registerTool("get_presentation_feedback_summary", {
|
|
5400
|
+
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.",
|
|
5401
|
+
inputSchema: getPresentationFeedbackSummaryInput
|
|
5402
|
+
}, async ({
|
|
5403
|
+
presentationId,
|
|
5404
|
+
variantId,
|
|
5405
|
+
sessionId,
|
|
5406
|
+
filter
|
|
5407
|
+
}) => {
|
|
5408
|
+
const client2 = getApiClient();
|
|
5409
|
+
const [stats, feedback] = await Promise.all([
|
|
5410
|
+
client2.getPresentationFeedbackStats(presentationId, variantId, sessionId),
|
|
5411
|
+
client2.getPresentationFeedback(presentationId, variantId, sessionId)
|
|
5412
|
+
]);
|
|
5413
|
+
const resolvedFilter = filter ?? "unresolved";
|
|
5414
|
+
const filtered = resolvedFilter === "all" ? feedback : feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
|
|
5415
|
+
if (filtered.length === 0) {
|
|
5416
|
+
return {
|
|
5417
|
+
content: [{ type: "text", text: "No feedback found matching the filter." }]
|
|
5418
|
+
};
|
|
5419
|
+
}
|
|
5420
|
+
const slideFeedback = filtered.filter((f) => f.type === "slide");
|
|
5421
|
+
const overallFeedback = filtered.filter((f) => f.type === "overall");
|
|
5422
|
+
const bySlide = new Map;
|
|
5423
|
+
for (const f of slideFeedback) {
|
|
5424
|
+
const key = f.slideId ?? "(unknown)";
|
|
5425
|
+
if (!bySlide.has(key))
|
|
5426
|
+
bySlide.set(key, []);
|
|
5427
|
+
bySlide.get(key).push(f);
|
|
5428
|
+
}
|
|
5429
|
+
let summary = `## Session (${stats.respondedCount}/${stats.totalInvites} responded, ${stats.unresolvedCount} unresolved)
|
|
5430
|
+
|
|
5431
|
+
`;
|
|
5432
|
+
const sortedSlides = [...bySlide.entries()].sort((a, b) => {
|
|
5433
|
+
const orderA = a[1][0]?.slideOrder ?? 0;
|
|
5434
|
+
const orderB = b[1][0]?.slideOrder ?? 0;
|
|
5435
|
+
return orderA - orderB;
|
|
5436
|
+
});
|
|
5437
|
+
for (const [, comments] of sortedSlides) {
|
|
5438
|
+
const first = comments[0];
|
|
5439
|
+
summary += `### Slide ${(first.slideOrder ?? 0) + 1}: "${first.slideTitle ?? "Untitled"}"
|
|
5440
|
+
`;
|
|
5441
|
+
for (const c of comments) {
|
|
5442
|
+
const status = c.resolved ? "RESOLVED" : "OPEN";
|
|
5443
|
+
summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
|
|
5444
|
+
`;
|
|
5445
|
+
if (c.emojiReactions && c.emojiReactions.length > 0) {
|
|
5446
|
+
summary += ` Reactions: ${c.emojiReactions.join(", ")}
|
|
5447
|
+
`;
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
summary += `
|
|
5451
|
+
`;
|
|
5452
|
+
}
|
|
5453
|
+
if (overallFeedback.length > 0) {
|
|
5454
|
+
summary += `### Overall Feedback
|
|
5455
|
+
`;
|
|
5456
|
+
for (const c of overallFeedback) {
|
|
5457
|
+
const status = c.resolved ? "RESOLVED" : "OPEN";
|
|
5458
|
+
summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
|
|
5459
|
+
`;
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
return {
|
|
5463
|
+
content: [{ type: "text", text: summary.trim() }]
|
|
5464
|
+
};
|
|
5465
|
+
});
|
|
5466
|
+
}
|
|
5467
|
+
function registerGetPresentationFeedbackDetail(server) {
|
|
5468
|
+
server.registerTool("get_presentation_feedback_detail", {
|
|
5469
|
+
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.",
|
|
5470
|
+
inputSchema: getPresentationFeedbackDetailInput
|
|
5471
|
+
}, async ({
|
|
5472
|
+
presentationId,
|
|
5473
|
+
variantId,
|
|
5474
|
+
sessionId,
|
|
5475
|
+
feedbackId,
|
|
5476
|
+
filter
|
|
5477
|
+
}) => {
|
|
5478
|
+
const client2 = getApiClient();
|
|
5479
|
+
const feedback = await client2.getPresentationFeedback(presentationId, variantId, sessionId);
|
|
5480
|
+
let filtered = feedback;
|
|
5481
|
+
if (feedbackId) {
|
|
5482
|
+
filtered = feedback.filter((f) => f.id === feedbackId);
|
|
5483
|
+
if (filtered.length === 0) {
|
|
5484
|
+
return {
|
|
5485
|
+
content: [
|
|
5486
|
+
{
|
|
5487
|
+
type: "text",
|
|
5488
|
+
text: `Feedback item ${feedbackId} not found in this session.`
|
|
5489
|
+
}
|
|
5490
|
+
]
|
|
5491
|
+
};
|
|
5492
|
+
}
|
|
5493
|
+
} else {
|
|
5494
|
+
const resolvedFilter = filter ?? "all";
|
|
5495
|
+
if (resolvedFilter !== "all") {
|
|
5496
|
+
filtered = feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
return {
|
|
5500
|
+
content: [
|
|
5501
|
+
{
|
|
5502
|
+
type: "text",
|
|
5503
|
+
text: JSON.stringify({ feedback: filtered }, null, 2)
|
|
5504
|
+
}
|
|
5505
|
+
]
|
|
5506
|
+
};
|
|
5507
|
+
});
|
|
5508
|
+
}
|
|
5509
|
+
function registerResolvePresentationFeedback(server) {
|
|
5510
|
+
server.registerTool("resolve_presentation_feedback", {
|
|
5511
|
+
description: "Set the resolved status on a presentation feedback item. Requires the feedback type (slide or overall) and the desired resolved state.",
|
|
5512
|
+
inputSchema: resolvePresentationFeedbackInput
|
|
5513
|
+
}, async ({
|
|
5514
|
+
presentationId,
|
|
5515
|
+
variantId,
|
|
5516
|
+
sessionId,
|
|
5517
|
+
feedbackId,
|
|
5518
|
+
type,
|
|
5519
|
+
resolved
|
|
5520
|
+
}) => {
|
|
5521
|
+
const client2 = getApiClient();
|
|
5522
|
+
const result = await client2.resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, { type, resolved });
|
|
5523
|
+
return {
|
|
5524
|
+
content: [
|
|
5525
|
+
{
|
|
5526
|
+
type: "text",
|
|
5527
|
+
text: JSON.stringify({
|
|
5528
|
+
success: true,
|
|
5529
|
+
feedbackId: result.id,
|
|
5530
|
+
resolved: result.resolved
|
|
5531
|
+
}, null, 2)
|
|
5532
|
+
}
|
|
5533
|
+
]
|
|
5534
|
+
};
|
|
5535
|
+
});
|
|
5536
|
+
}
|
|
5537
|
+
function registerAddPresentationReviewer(server) {
|
|
5538
|
+
server.registerTool("add_presentation_reviewer", {
|
|
5539
|
+
description: "Add a reviewer to an active presentation feedback session. Returns a unique review URL for the new reviewer.",
|
|
5540
|
+
inputSchema: addPresentationReviewerInput
|
|
5541
|
+
}, async ({
|
|
5542
|
+
presentationId,
|
|
5543
|
+
variantId,
|
|
5544
|
+
sessionId,
|
|
5545
|
+
name,
|
|
5546
|
+
email
|
|
5547
|
+
}) => {
|
|
5548
|
+
const client2 = getApiClient();
|
|
5549
|
+
const invite = await client2.addPresentationReviewer(presentationId, variantId, sessionId, {
|
|
5550
|
+
name,
|
|
5551
|
+
email
|
|
5552
|
+
});
|
|
5553
|
+
const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
|
|
5554
|
+
return {
|
|
5555
|
+
content: [
|
|
5556
|
+
{
|
|
5557
|
+
type: "text",
|
|
5558
|
+
text: JSON.stringify({
|
|
5559
|
+
success: true,
|
|
5560
|
+
inviteId: invite.id,
|
|
5561
|
+
reviewUrl,
|
|
5562
|
+
reviewerName: invite.reviewerName,
|
|
5563
|
+
reviewerEmail: invite.reviewerEmail
|
|
5564
|
+
}, null, 2)
|
|
5565
|
+
}
|
|
5566
|
+
]
|
|
5567
|
+
};
|
|
5568
|
+
});
|
|
5569
|
+
}
|
|
5570
|
+
function registerListVerificationRuns(server) {
|
|
5571
|
+
server.registerTool("list_verification_runs", {
|
|
5572
|
+
description: "List all verification runs for a roadmap item. Returns summary data without full results JSON.",
|
|
5573
|
+
inputSchema: listVerificationRunsInput
|
|
5574
|
+
}, async ({ roadmapId }) => {
|
|
5575
|
+
const client2 = getApiClient();
|
|
5576
|
+
const response = await client2.listVerificationRuns(roadmapId);
|
|
5577
|
+
return {
|
|
5578
|
+
content: [
|
|
5579
|
+
{
|
|
5580
|
+
type: "text",
|
|
5581
|
+
text: JSON.stringify(response, null, 2)
|
|
5582
|
+
}
|
|
5583
|
+
]
|
|
5584
|
+
};
|
|
5585
|
+
});
|
|
5586
|
+
}
|
|
5587
|
+
function registerGetVerificationRun(server) {
|
|
5588
|
+
server.registerTool("get_verification_run", {
|
|
5589
|
+
description: "Get full details of a verification run including outcome results, visual comparisons, edge case results, and fix prompt.",
|
|
5590
|
+
inputSchema: getVerificationRunInput
|
|
5591
|
+
}, async ({ roadmapId, runId }) => {
|
|
5592
|
+
const client2 = getApiClient();
|
|
5593
|
+
const response = await client2.getVerificationRun(roadmapId, runId);
|
|
5594
|
+
return {
|
|
5595
|
+
content: [
|
|
5596
|
+
{
|
|
5597
|
+
type: "text",
|
|
5598
|
+
text: JSON.stringify(response, null, 2)
|
|
5599
|
+
}
|
|
5600
|
+
]
|
|
5601
|
+
};
|
|
5602
|
+
});
|
|
5603
|
+
}
|
|
5604
|
+
function registerCreateVerificationRun(server) {
|
|
5605
|
+
server.registerTool("create_verification_run", {
|
|
5606
|
+
description: "Create a new verification run record. Call this at the start of a QA verification to track the run.",
|
|
5607
|
+
inputSchema: createVerificationRunInput
|
|
5608
|
+
}, async ({
|
|
5609
|
+
roadmapId,
|
|
5610
|
+
appUrl,
|
|
5611
|
+
verificationTypes,
|
|
5612
|
+
totalOutcomes
|
|
5613
|
+
}) => {
|
|
5614
|
+
const client2 = getApiClient();
|
|
5615
|
+
const response = await client2.createVerificationRun(roadmapId, {
|
|
5616
|
+
appUrl,
|
|
5617
|
+
verificationTypes,
|
|
5618
|
+
totalOutcomes
|
|
5619
|
+
});
|
|
5620
|
+
return {
|
|
5621
|
+
content: [
|
|
5622
|
+
{
|
|
5623
|
+
type: "text",
|
|
5624
|
+
text: JSON.stringify(response, null, 2)
|
|
5625
|
+
}
|
|
5626
|
+
]
|
|
5627
|
+
};
|
|
5628
|
+
});
|
|
5629
|
+
}
|
|
5630
|
+
function registerUpdateVerificationRun(server) {
|
|
5631
|
+
server.registerTool("update_verification_run", {
|
|
5632
|
+
description: "Update a verification run with results, status, and fix prompt. Call this as verification completes to save results.",
|
|
5633
|
+
inputSchema: updateVerificationRunInput
|
|
5634
|
+
}, async ({
|
|
5635
|
+
roadmapId,
|
|
5636
|
+
runId,
|
|
5637
|
+
...rest
|
|
5638
|
+
}) => {
|
|
5639
|
+
const client2 = getApiClient();
|
|
5640
|
+
const response = await client2.updateVerificationRun(roadmapId, runId, rest);
|
|
5641
|
+
return {
|
|
5642
|
+
content: [
|
|
5643
|
+
{
|
|
5644
|
+
type: "text",
|
|
5645
|
+
text: JSON.stringify(response, null, 2)
|
|
5646
|
+
}
|
|
5647
|
+
]
|
|
5648
|
+
};
|
|
5649
|
+
});
|
|
5650
|
+
}
|
|
5209
5651
|
|
|
5210
5652
|
// src/index.ts
|
|
5211
5653
|
async function main() {
|