@ourroadmaps/mcp 0.14.0 → 0.16.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 +384 -127
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
2
20
|
|
|
3
21
|
// src/index.ts
|
|
4
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -370,6 +388,14 @@ var wireframeSchema = z8.object({
|
|
|
370
388
|
imageUrl: z8.string().nullable(),
|
|
371
389
|
order: z8.number().int()
|
|
372
390
|
});
|
|
391
|
+
var prototypeSchema = z8.object({
|
|
392
|
+
id: z8.string().uuid(),
|
|
393
|
+
publicUrl: z8.string().url(),
|
|
394
|
+
expiresAt: z8.string().datetime(),
|
|
395
|
+
fileCount: z8.number().int().positive(),
|
|
396
|
+
entryPoint: z8.string(),
|
|
397
|
+
createdAt: z8.string().datetime()
|
|
398
|
+
});
|
|
373
399
|
var featureLinkSchema = z8.object({
|
|
374
400
|
id: z8.string().uuid(),
|
|
375
401
|
featureId: z8.string().uuid(),
|
|
@@ -400,6 +426,7 @@ var phaseReleaseSchema = z8.object({
|
|
|
400
426
|
var roadmapDetailSchema = roadmapSchema.extend({
|
|
401
427
|
prd: prdSchema.nullable(),
|
|
402
428
|
wireframes: z8.array(wireframeSchema),
|
|
429
|
+
prototypes: z8.array(prototypeSchema),
|
|
403
430
|
brainstormMedia: z8.array(brainstormMediaSchema),
|
|
404
431
|
brainstormNotes: z8.string().nullable(),
|
|
405
432
|
featureLinks: z8.array(featureLinkSchema),
|
|
@@ -438,8 +465,28 @@ var updateScenarioSchema = z9.object({
|
|
|
438
465
|
order: z9.number().int().optional()
|
|
439
466
|
});
|
|
440
467
|
var scenarioListSchema = z9.array(scenarioSchema);
|
|
441
|
-
// src/
|
|
468
|
+
// ../../packages/shared/src/schemas/status-update.ts
|
|
442
469
|
import { z as z10 } from "zod";
|
|
470
|
+
var statusUpdateItemSchema = z10.object({
|
|
471
|
+
id: z10.string().uuid(),
|
|
472
|
+
roadmapItemId: z10.string().uuid(),
|
|
473
|
+
titleAtSnapshot: z10.string(),
|
|
474
|
+
statusAtSnapshot: z10.string(),
|
|
475
|
+
designWalkthroughUrl: z10.string().nullable(),
|
|
476
|
+
releaseWalkthroughUrl: z10.string().nullable()
|
|
477
|
+
});
|
|
478
|
+
var statusUpdateSchema = z10.object({
|
|
479
|
+
id: z10.string().uuid(),
|
|
480
|
+
title: z10.string().nullable(),
|
|
481
|
+
startDate: z10.string(),
|
|
482
|
+
endDate: z10.string(),
|
|
483
|
+
content: z10.string(),
|
|
484
|
+
createdAt: z10.string(),
|
|
485
|
+
items: z10.array(statusUpdateItemSchema).optional()
|
|
486
|
+
});
|
|
487
|
+
var statusUpdateListSchema = z10.array(statusUpdateSchema);
|
|
488
|
+
// src/tools/index.ts
|
|
489
|
+
import { z as z11 } from "zod";
|
|
443
490
|
|
|
444
491
|
// src/auth.ts
|
|
445
492
|
function getCredentials() {
|
|
@@ -876,6 +923,32 @@ class ApiClient {
|
|
|
876
923
|
});
|
|
877
924
|
return response.data;
|
|
878
925
|
}
|
|
926
|
+
async getPrototypeUploadUrls(roadmapId, files) {
|
|
927
|
+
const response = await this.request(`/v1/roadmaps/${roadmapId}/prototypes/upload-urls`, {
|
|
928
|
+
method: "POST",
|
|
929
|
+
body: JSON.stringify({ files })
|
|
930
|
+
});
|
|
931
|
+
return response.data;
|
|
932
|
+
}
|
|
933
|
+
async createPrototype(roadmapId, data) {
|
|
934
|
+
const response = await this.request(`/v1/roadmaps/${roadmapId}/prototypes`, {
|
|
935
|
+
method: "POST",
|
|
936
|
+
body: JSON.stringify(data)
|
|
937
|
+
});
|
|
938
|
+
return response.data;
|
|
939
|
+
}
|
|
940
|
+
async uploadFile(uploadUrl, content, contentType) {
|
|
941
|
+
const response = await fetch(uploadUrl, {
|
|
942
|
+
method: "PUT",
|
|
943
|
+
body: content,
|
|
944
|
+
headers: {
|
|
945
|
+
"Content-Type": contentType
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
if (!response.ok) {
|
|
949
|
+
throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
879
952
|
}
|
|
880
953
|
var client = null;
|
|
881
954
|
function getApiClient() {
|
|
@@ -952,16 +1025,17 @@ function registerAllTools(server) {
|
|
|
952
1025
|
registerDeleteProductDesignMedia(server);
|
|
953
1026
|
registerUploadDesignWalkthrough(server);
|
|
954
1027
|
registerUploadReleaseWalkthrough(server);
|
|
1028
|
+
registerPublishPrototype(server);
|
|
955
1029
|
}
|
|
956
1030
|
function registerSearchRoadmaps(server) {
|
|
957
1031
|
server.registerTool("search_roadmaps", {
|
|
958
1032
|
description: "Search for roadmap items by title, status, or horizon. Returns a list of matching roadmap items with basic info.",
|
|
959
1033
|
inputSchema: {
|
|
960
|
-
query:
|
|
1034
|
+
query: z11.string().optional().describe("Search query to match against title or description"),
|
|
961
1035
|
status: roadmapStatusSchema.optional().describe("Filter by status"),
|
|
962
1036
|
horizon: horizonSchema.optional().describe("Filter by planning horizon"),
|
|
963
|
-
limit:
|
|
964
|
-
offset:
|
|
1037
|
+
limit: z11.number().int().min(1).max(100).optional().describe("Max items to return (default 10)"),
|
|
1038
|
+
offset: z11.number().int().min(0).optional().describe("Number of items to skip (default 0)")
|
|
965
1039
|
}
|
|
966
1040
|
}, async ({
|
|
967
1041
|
query,
|
|
@@ -1008,7 +1082,7 @@ function registerGetRoadmap(server) {
|
|
|
1008
1082
|
server.registerTool("get_roadmap", {
|
|
1009
1083
|
description: "Get full details of a roadmap item including PRD, wireframes, brainstorm media, linked features, epics, and stories.",
|
|
1010
1084
|
inputSchema: {
|
|
1011
|
-
id:
|
|
1085
|
+
id: z11.string().describe("The UUID of the roadmap item")
|
|
1012
1086
|
}
|
|
1013
1087
|
}, async ({ id }) => {
|
|
1014
1088
|
const client2 = getApiClient();
|
|
@@ -1062,7 +1136,7 @@ function registerSearchFeatures(server) {
|
|
|
1062
1136
|
server.registerTool("search_features", {
|
|
1063
1137
|
description: "Search for features and feature areas by name. Returns a list of matching features with basic info.",
|
|
1064
1138
|
inputSchema: {
|
|
1065
|
-
query:
|
|
1139
|
+
query: z11.string().optional().describe("Search query to match against name"),
|
|
1066
1140
|
type: featureTypeSchema.optional().describe("Filter by type (feature or area)")
|
|
1067
1141
|
}
|
|
1068
1142
|
}, async ({ query, type }) => {
|
|
@@ -1094,7 +1168,7 @@ function registerGetFeature(server) {
|
|
|
1094
1168
|
server.registerTool("get_feature", {
|
|
1095
1169
|
description: "Get full details of a feature including outcomes, child features, and linked roadmap items.",
|
|
1096
1170
|
inputSchema: {
|
|
1097
|
-
id:
|
|
1171
|
+
id: z11.string().describe("The UUID of the feature")
|
|
1098
1172
|
}
|
|
1099
1173
|
}, async ({ id }) => {
|
|
1100
1174
|
const client2 = getApiClient();
|
|
@@ -1133,7 +1207,7 @@ function registerSearchIdeas(server) {
|
|
|
1133
1207
|
server.registerTool("search_ideas", {
|
|
1134
1208
|
description: "Search for ideas by title or status. Returns a list of matching ideas with basic info.",
|
|
1135
1209
|
inputSchema: {
|
|
1136
|
-
query:
|
|
1210
|
+
query: z11.string().optional().describe("Search query to match against title or description"),
|
|
1137
1211
|
status: ideaStatusSchema.optional().describe("Filter by status")
|
|
1138
1212
|
}
|
|
1139
1213
|
}, async ({ query, status }) => {
|
|
@@ -1233,9 +1307,9 @@ function registerCaptureIdea(server) {
|
|
|
1233
1307
|
server.registerTool("capture_idea", {
|
|
1234
1308
|
description: "Quickly capture a new idea. Ideas are suggestions that can later be reviewed and potentially converted to roadmap items.",
|
|
1235
1309
|
inputSchema: {
|
|
1236
|
-
title:
|
|
1237
|
-
description:
|
|
1238
|
-
source:
|
|
1310
|
+
title: z11.string().describe("Title of the idea"),
|
|
1311
|
+
description: z11.string().optional().describe("Detailed description of the idea"),
|
|
1312
|
+
source: z11.string().optional().describe('Source of the idea (defaults to "claude-code")')
|
|
1239
1313
|
}
|
|
1240
1314
|
}, async ({
|
|
1241
1315
|
title,
|
|
@@ -1272,7 +1346,7 @@ function registerCreateRoadmapItem(server) {
|
|
|
1272
1346
|
server.registerTool("create_roadmap_item", {
|
|
1273
1347
|
description: "Create a new roadmap item. Use this to add planned work to the roadmap.",
|
|
1274
1348
|
inputSchema: {
|
|
1275
|
-
title:
|
|
1349
|
+
title: z11.string().describe("Title of the roadmap item"),
|
|
1276
1350
|
status: roadmapStatusSchema.optional().describe('Status (defaults to "not_started")'),
|
|
1277
1351
|
horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")')
|
|
1278
1352
|
}
|
|
@@ -1305,23 +1379,23 @@ function registerCreateRoadmapItem(server) {
|
|
|
1305
1379
|
};
|
|
1306
1380
|
});
|
|
1307
1381
|
}
|
|
1308
|
-
var effortSizeSchema =
|
|
1382
|
+
var effortSizeSchema = z11.enum(["xs", "s", "m", "l", "xl"]);
|
|
1309
1383
|
function registerUpdateRoadmapItem(server) {
|
|
1310
1384
|
server.registerTool("update_roadmap_item", {
|
|
1311
1385
|
description: "Update an existing roadmap item. Can update title, status, horizon, value, effort, order, prompt, or brainstorm notes.",
|
|
1312
1386
|
inputSchema: {
|
|
1313
|
-
id:
|
|
1314
|
-
title:
|
|
1387
|
+
id: z11.string().describe("The UUID of the roadmap item to update"),
|
|
1388
|
+
title: z11.string().optional().describe("New title"),
|
|
1315
1389
|
status: roadmapStatusSchema.optional().describe("New status"),
|
|
1316
1390
|
horizon: horizonSchema.optional().describe("New planning horizon"),
|
|
1317
|
-
value:
|
|
1391
|
+
value: z11.number().int().min(1).max(3).nullable().optional().describe("Value rating (1-3 stars, where 3 is highest value)"),
|
|
1318
1392
|
effort: effortSizeSchema.nullable().optional().describe("Effort estimate (xs=extra small, s=small, m=medium, l=large, xl=extra large)"),
|
|
1319
|
-
order:
|
|
1320
|
-
designDescription:
|
|
1321
|
-
planDescription:
|
|
1322
|
-
buildDescription:
|
|
1323
|
-
releaseDescription:
|
|
1324
|
-
prompt:
|
|
1393
|
+
order: z11.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
|
|
1394
|
+
designDescription: z11.string().nullable().optional().describe("Description for the Design phase"),
|
|
1395
|
+
planDescription: z11.string().nullable().optional().describe("Description for the Planning phase"),
|
|
1396
|
+
buildDescription: z11.string().nullable().optional().describe("Description for the Build phase"),
|
|
1397
|
+
releaseDescription: z11.string().nullable().optional().describe("Description for the Release phase"),
|
|
1398
|
+
prompt: z11.string().nullable().optional().describe("Build prompt for the roadmap item")
|
|
1325
1399
|
}
|
|
1326
1400
|
}, async ({
|
|
1327
1401
|
id,
|
|
@@ -1403,12 +1477,12 @@ function registerAddFeature(server) {
|
|
|
1403
1477
|
server.registerTool("add_feature", {
|
|
1404
1478
|
description: "Create a new feature with optional outcomes. Features represent capabilities or functionality areas.",
|
|
1405
1479
|
inputSchema: {
|
|
1406
|
-
name:
|
|
1407
|
-
description:
|
|
1480
|
+
name: z11.string().describe("Name of the feature"),
|
|
1481
|
+
description: z11.string().optional().describe("Description of the feature"),
|
|
1408
1482
|
type: featureTypeSchema.optional().describe('Type - "feature" for specific functionality, "area" for grouping (defaults to "feature")'),
|
|
1409
|
-
parentId:
|
|
1410
|
-
outcomes:
|
|
1411
|
-
linkToRoadmapId:
|
|
1483
|
+
parentId: z11.string().optional().describe("UUID of parent feature/area to nest under"),
|
|
1484
|
+
outcomes: z11.array(z11.string()).optional().describe("List of expected outcomes for this feature"),
|
|
1485
|
+
linkToRoadmapId: z11.string().optional().describe("UUID of roadmap item to link this feature to")
|
|
1412
1486
|
}
|
|
1413
1487
|
}, async ({
|
|
1414
1488
|
name,
|
|
@@ -1455,10 +1529,10 @@ function registerSavePrd(server) {
|
|
|
1455
1529
|
server.registerTool("save_prd", {
|
|
1456
1530
|
description: "Save or update the PRD (Product Requirements Document) content for a roadmap item. Content should be markdown.",
|
|
1457
1531
|
inputSchema: {
|
|
1458
|
-
roadmapId:
|
|
1459
|
-
what:
|
|
1460
|
-
why:
|
|
1461
|
-
outcomes:
|
|
1532
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
1533
|
+
what: z11.string().nullable().describe("What is being built - the feature description"),
|
|
1534
|
+
why: z11.string().nullable().describe("Why this is being built - the business justification"),
|
|
1535
|
+
outcomes: z11.array(z11.string()).optional().describe("List of expected outcomes/success criteria")
|
|
1462
1536
|
}
|
|
1463
1537
|
}, async ({
|
|
1464
1538
|
roadmapId,
|
|
@@ -1496,8 +1570,8 @@ function registerUpdateBrainstormNotes(server) {
|
|
|
1496
1570
|
server.registerTool("update_brainstorm_notes", {
|
|
1497
1571
|
description: "Update the brainstorm notes for a roadmap item. Use this to capture ideas, questions, and research notes.",
|
|
1498
1572
|
inputSchema: {
|
|
1499
|
-
roadmapId:
|
|
1500
|
-
notes:
|
|
1573
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
1574
|
+
notes: z11.string().describe("The brainstorm notes content")
|
|
1501
1575
|
}
|
|
1502
1576
|
}, async ({ roadmapId, notes }) => {
|
|
1503
1577
|
const client2 = getApiClient();
|
|
@@ -1526,7 +1600,7 @@ function registerDeleteRoadmapItem(server) {
|
|
|
1526
1600
|
server.registerTool("delete_roadmap_item", {
|
|
1527
1601
|
description: "Delete a roadmap item. This is a soft delete - the item can potentially be recovered.",
|
|
1528
1602
|
inputSchema: {
|
|
1529
|
-
id:
|
|
1603
|
+
id: z11.string().describe("The UUID of the roadmap item to delete")
|
|
1530
1604
|
}
|
|
1531
1605
|
}, async ({ id }) => {
|
|
1532
1606
|
const client2 = getApiClient();
|
|
@@ -1548,9 +1622,9 @@ function registerReorderRoadmaps(server) {
|
|
|
1548
1622
|
server.registerTool("reorder_roadmaps", {
|
|
1549
1623
|
description: "Bulk reorder roadmap items by setting their order values. Use this to prioritize and organize the roadmap. Lower order values appear first.",
|
|
1550
1624
|
inputSchema: {
|
|
1551
|
-
items:
|
|
1552
|
-
id:
|
|
1553
|
-
order:
|
|
1625
|
+
items: z11.array(z11.object({
|
|
1626
|
+
id: z11.string().describe("The UUID of the roadmap item"),
|
|
1627
|
+
order: z11.number().int().min(0).describe("The new order value (0-based, lower = higher priority)")
|
|
1554
1628
|
})).describe("Array of roadmap items with their new order values")
|
|
1555
1629
|
}
|
|
1556
1630
|
}, async ({ items }) => {
|
|
@@ -1574,10 +1648,10 @@ function registerUpdateFeature(server) {
|
|
|
1574
1648
|
server.registerTool("update_feature", {
|
|
1575
1649
|
description: "Update an existing feature. Can update name, type, or parent.",
|
|
1576
1650
|
inputSchema: {
|
|
1577
|
-
id:
|
|
1578
|
-
name:
|
|
1651
|
+
id: z11.string().describe("The UUID of the feature to update"),
|
|
1652
|
+
name: z11.string().optional().describe("New name for the feature"),
|
|
1579
1653
|
type: featureTypeSchema.optional().describe('New type - "feature" or "area"'),
|
|
1580
|
-
parentId:
|
|
1654
|
+
parentId: z11.string().nullable().optional().describe("New parent feature/area UUID, or null to move to root")
|
|
1581
1655
|
}
|
|
1582
1656
|
}, async ({
|
|
1583
1657
|
id,
|
|
@@ -1616,7 +1690,7 @@ function registerDeleteFeature(server) {
|
|
|
1616
1690
|
server.registerTool("delete_feature", {
|
|
1617
1691
|
description: "Delete a feature. This is a soft delete that also deletes all child features.",
|
|
1618
1692
|
inputSchema: {
|
|
1619
|
-
id:
|
|
1693
|
+
id: z11.string().describe("The UUID of the feature to delete")
|
|
1620
1694
|
}
|
|
1621
1695
|
}, async ({ id }) => {
|
|
1622
1696
|
const client2 = getApiClient();
|
|
@@ -1638,7 +1712,7 @@ function registerGetIdea(server) {
|
|
|
1638
1712
|
server.registerTool("get_idea", {
|
|
1639
1713
|
description: "Get full details of a single idea by ID.",
|
|
1640
1714
|
inputSchema: {
|
|
1641
|
-
id:
|
|
1715
|
+
id: z11.string().describe("The UUID of the idea")
|
|
1642
1716
|
}
|
|
1643
1717
|
}, async ({ id }) => {
|
|
1644
1718
|
const client2 = getApiClient();
|
|
@@ -1667,12 +1741,12 @@ function registerUpdateIdea(server) {
|
|
|
1667
1741
|
server.registerTool("update_idea", {
|
|
1668
1742
|
description: "Update an existing idea. Can update title, description, status, value, or effort.",
|
|
1669
1743
|
inputSchema: {
|
|
1670
|
-
id:
|
|
1671
|
-
title:
|
|
1672
|
-
description:
|
|
1744
|
+
id: z11.string().describe("The UUID of the idea to update"),
|
|
1745
|
+
title: z11.string().optional().describe("New title"),
|
|
1746
|
+
description: z11.string().nullable().optional().describe("New description"),
|
|
1673
1747
|
status: ideaStatusSchema.optional().describe("New status"),
|
|
1674
|
-
value:
|
|
1675
|
-
effort:
|
|
1748
|
+
value: z11.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated value"),
|
|
1749
|
+
effort: z11.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated effort")
|
|
1676
1750
|
}
|
|
1677
1751
|
}, async ({
|
|
1678
1752
|
id,
|
|
@@ -1719,7 +1793,7 @@ function registerDeleteIdea(server) {
|
|
|
1719
1793
|
server.registerTool("delete_idea", {
|
|
1720
1794
|
description: "Delete an idea. This is a soft delete.",
|
|
1721
1795
|
inputSchema: {
|
|
1722
|
-
id:
|
|
1796
|
+
id: z11.string().describe("The UUID of the idea to delete")
|
|
1723
1797
|
}
|
|
1724
1798
|
}, async ({ id }) => {
|
|
1725
1799
|
const client2 = getApiClient();
|
|
@@ -1758,8 +1832,8 @@ function registerUpdateStrategy(server) {
|
|
|
1758
1832
|
server.registerTool("update_strategy", {
|
|
1759
1833
|
description: "Update the organization strategy. Can update vision, mission, or both. Use this to set or refine the high-level direction.",
|
|
1760
1834
|
inputSchema: {
|
|
1761
|
-
vision:
|
|
1762
|
-
mission:
|
|
1835
|
+
vision: z11.string().nullable().optional().describe("The vision statement - where the product is headed"),
|
|
1836
|
+
mission: z11.string().nullable().optional().describe("The mission statement - why the product exists")
|
|
1763
1837
|
}
|
|
1764
1838
|
}, async ({ vision, mission }) => {
|
|
1765
1839
|
const client2 = getApiClient();
|
|
@@ -1807,8 +1881,8 @@ function registerCreateScenario(server) {
|
|
|
1807
1881
|
server.registerTool("create_scenario", {
|
|
1808
1882
|
description: "Create a new user scenario. Scenarios describe user workflows and how they accomplish goals.",
|
|
1809
1883
|
inputSchema: {
|
|
1810
|
-
title:
|
|
1811
|
-
description:
|
|
1884
|
+
title: z11.string().describe('Title of the scenario (e.g., "User creates their first roadmap")'),
|
|
1885
|
+
description: z11.string().nullable().optional().describe("Detailed description of the scenario workflow")
|
|
1812
1886
|
}
|
|
1813
1887
|
}, async ({ title, description }) => {
|
|
1814
1888
|
const client2 = getApiClient();
|
|
@@ -1837,9 +1911,9 @@ function registerUpdateScenario(server) {
|
|
|
1837
1911
|
server.registerTool("update_scenario", {
|
|
1838
1912
|
description: "Update an existing scenario.",
|
|
1839
1913
|
inputSchema: {
|
|
1840
|
-
id:
|
|
1841
|
-
title:
|
|
1842
|
-
description:
|
|
1914
|
+
id: z11.string().describe("The UUID of the scenario to update"),
|
|
1915
|
+
title: z11.string().optional().describe("New title"),
|
|
1916
|
+
description: z11.string().nullable().optional().describe("New description")
|
|
1843
1917
|
}
|
|
1844
1918
|
}, async ({
|
|
1845
1919
|
id,
|
|
@@ -1874,7 +1948,7 @@ function registerDeleteScenario(server) {
|
|
|
1874
1948
|
server.registerTool("delete_scenario", {
|
|
1875
1949
|
description: "Delete a scenario. This is a soft delete.",
|
|
1876
1950
|
inputSchema: {
|
|
1877
|
-
id:
|
|
1951
|
+
id: z11.string().describe("The UUID of the scenario to delete")
|
|
1878
1952
|
}
|
|
1879
1953
|
}, async ({ id }) => {
|
|
1880
1954
|
const client2 = getApiClient();
|
|
@@ -1889,7 +1963,7 @@ function registerDeleteScenario(server) {
|
|
|
1889
1963
|
};
|
|
1890
1964
|
});
|
|
1891
1965
|
}
|
|
1892
|
-
var productTypeSchema2 =
|
|
1966
|
+
var productTypeSchema2 = z11.enum([
|
|
1893
1967
|
"brand",
|
|
1894
1968
|
"product",
|
|
1895
1969
|
"app",
|
|
@@ -1902,8 +1976,8 @@ function registerCreateProduct(server) {
|
|
|
1902
1976
|
description: "Create a new product, app, brand, or service. Products represent what the organization builds and offers.",
|
|
1903
1977
|
inputSchema: {
|
|
1904
1978
|
type: productTypeSchema2.describe("Type of product"),
|
|
1905
|
-
name:
|
|
1906
|
-
parentId:
|
|
1979
|
+
name: z11.string().describe("Name of the product"),
|
|
1980
|
+
parentId: z11.string().nullable().optional().describe("UUID of parent product to nest under")
|
|
1907
1981
|
}
|
|
1908
1982
|
}, async ({
|
|
1909
1983
|
type,
|
|
@@ -1938,9 +2012,9 @@ function registerUpdateProduct(server) {
|
|
|
1938
2012
|
server.registerTool("update_product", {
|
|
1939
2013
|
description: "Update an existing product.",
|
|
1940
2014
|
inputSchema: {
|
|
1941
|
-
id:
|
|
1942
|
-
name:
|
|
1943
|
-
parentId:
|
|
2015
|
+
id: z11.string().describe("The UUID of the product to update"),
|
|
2016
|
+
name: z11.string().optional().describe("New name"),
|
|
2017
|
+
parentId: z11.string().nullable().optional().describe("New parent product UUID, or null to move to root")
|
|
1944
2018
|
}
|
|
1945
2019
|
}, async ({ id, name, parentId }) => {
|
|
1946
2020
|
const client2 = getApiClient();
|
|
@@ -1972,7 +2046,7 @@ function registerDeleteProduct(server) {
|
|
|
1972
2046
|
server.registerTool("delete_product", {
|
|
1973
2047
|
description: "Delete a product. This is a soft delete that also deletes all child products.",
|
|
1974
2048
|
inputSchema: {
|
|
1975
|
-
id:
|
|
2049
|
+
id: z11.string().describe("The UUID of the product to delete")
|
|
1976
2050
|
}
|
|
1977
2051
|
}, async ({ id }) => {
|
|
1978
2052
|
const client2 = getApiClient();
|
|
@@ -1995,7 +2069,7 @@ function registerGetProduct(server) {
|
|
|
1995
2069
|
server.registerTool("get_product", {
|
|
1996
2070
|
description: "Get full details of a product by ID, including its documentation (design system and ADRs).",
|
|
1997
2071
|
inputSchema: {
|
|
1998
|
-
id:
|
|
2072
|
+
id: z11.string().describe("The UUID of the product")
|
|
1999
2073
|
}
|
|
2000
2074
|
}, async ({ id }) => {
|
|
2001
2075
|
const client2 = getApiClient();
|
|
@@ -2032,7 +2106,7 @@ function registerSearchProducts(server) {
|
|
|
2032
2106
|
server.registerTool("search_products", {
|
|
2033
2107
|
description: "Search for products by name. Returns a list of matching products with basic info.",
|
|
2034
2108
|
inputSchema: {
|
|
2035
|
-
query:
|
|
2109
|
+
query: z11.string().optional().describe("Search query to match against product name"),
|
|
2036
2110
|
type: productTypeSchema2.optional().describe("Filter by product type")
|
|
2037
2111
|
}
|
|
2038
2112
|
}, async ({ query, type }) => {
|
|
@@ -2067,7 +2141,7 @@ function registerGetProductDocumentation(server) {
|
|
|
2067
2141
|
server.registerTool("get_product_documentation", {
|
|
2068
2142
|
description: "Get the documentation (design system and ADRs) for a product. Use this to read existing documentation before updating.",
|
|
2069
2143
|
inputSchema: {
|
|
2070
|
-
productId:
|
|
2144
|
+
productId: z11.string().describe("The UUID of the product")
|
|
2071
2145
|
}
|
|
2072
2146
|
}, async ({ productId }) => {
|
|
2073
2147
|
const client2 = getApiClient();
|
|
@@ -2095,9 +2169,9 @@ function registerUpdateProductDocumentation(server) {
|
|
|
2095
2169
|
server.registerTool("update_product_documentation", {
|
|
2096
2170
|
description: "Update the documentation for a product. Use this to keep design system and ADRs up to date. Creates documentation if it does not exist.",
|
|
2097
2171
|
inputSchema: {
|
|
2098
|
-
productId:
|
|
2099
|
-
designSystem:
|
|
2100
|
-
adrs:
|
|
2172
|
+
productId: z11.string().describe("The UUID of the product"),
|
|
2173
|
+
designSystem: z11.string().nullable().optional().describe("Design system documentation - colors, typography, spacing, components. Pass null to clear."),
|
|
2174
|
+
adrs: z11.string().nullable().optional().describe("Architecture Decision Records - document key technical decisions. Pass null to clear.")
|
|
2101
2175
|
}
|
|
2102
2176
|
}, async ({
|
|
2103
2177
|
productId,
|
|
@@ -2130,16 +2204,16 @@ function registerUpdateProductDocumentation(server) {
|
|
|
2130
2204
|
};
|
|
2131
2205
|
});
|
|
2132
2206
|
}
|
|
2133
|
-
var audienceTypeSchema2 =
|
|
2207
|
+
var audienceTypeSchema2 = z11.enum(["stakeholder", "user_persona"]);
|
|
2134
2208
|
function registerCreateAudience(server) {
|
|
2135
2209
|
server.registerTool("create_audience", {
|
|
2136
2210
|
description: "Create a new audience member - either a stakeholder or user persona. Audiences represent who the product serves.",
|
|
2137
2211
|
inputSchema: {
|
|
2138
2212
|
type: audienceTypeSchema2.describe("Type of audience - stakeholder or user_persona"),
|
|
2139
|
-
role:
|
|
2140
|
-
likes:
|
|
2141
|
-
dislikes:
|
|
2142
|
-
priorities:
|
|
2213
|
+
role: z11.string().describe('Role or title of the audience (e.g., "Product Manager", "End User")'),
|
|
2214
|
+
likes: z11.string().nullable().optional().describe("What this audience likes or values"),
|
|
2215
|
+
dislikes: z11.string().nullable().optional().describe("What this audience dislikes or avoids"),
|
|
2216
|
+
priorities: z11.string().nullable().optional().describe("Key priorities for this audience")
|
|
2143
2217
|
}
|
|
2144
2218
|
}, async ({
|
|
2145
2219
|
type,
|
|
@@ -2180,12 +2254,12 @@ function registerUpdateAudience(server) {
|
|
|
2180
2254
|
server.registerTool("update_audience", {
|
|
2181
2255
|
description: "Update an existing audience member.",
|
|
2182
2256
|
inputSchema: {
|
|
2183
|
-
id:
|
|
2257
|
+
id: z11.string().describe("The UUID of the audience to update"),
|
|
2184
2258
|
type: audienceTypeSchema2.optional().describe("New type"),
|
|
2185
|
-
role:
|
|
2186
|
-
likes:
|
|
2187
|
-
dislikes:
|
|
2188
|
-
priorities:
|
|
2259
|
+
role: z11.string().optional().describe("New role"),
|
|
2260
|
+
likes: z11.string().nullable().optional().describe("New likes"),
|
|
2261
|
+
dislikes: z11.string().nullable().optional().describe("New dislikes"),
|
|
2262
|
+
priorities: z11.string().nullable().optional().describe("New priorities")
|
|
2189
2263
|
}
|
|
2190
2264
|
}, async ({
|
|
2191
2265
|
id,
|
|
@@ -2232,7 +2306,7 @@ function registerDeleteAudience(server) {
|
|
|
2232
2306
|
server.registerTool("delete_audience", {
|
|
2233
2307
|
description: "Delete an audience member. This is a soft delete.",
|
|
2234
2308
|
inputSchema: {
|
|
2235
|
-
id:
|
|
2309
|
+
id: z11.string().describe("The UUID of the audience to delete")
|
|
2236
2310
|
}
|
|
2237
2311
|
}, async ({ id }) => {
|
|
2238
2312
|
const client2 = getApiClient();
|
|
@@ -2274,9 +2348,9 @@ function registerGetHistory(server) {
|
|
|
2274
2348
|
server.registerTool("get_history", {
|
|
2275
2349
|
description: "Get raw history events for a date range. Returns full event details including payloads. " + "Use entityType or entityId filters to narrow results. For status reports, prefer " + "get_history_summary to avoid context overflow.",
|
|
2276
2350
|
inputSchema: {
|
|
2277
|
-
startDate:
|
|
2278
|
-
endDate:
|
|
2279
|
-
entityType:
|
|
2351
|
+
startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
|
|
2352
|
+
endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format"),
|
|
2353
|
+
entityType: z11.enum([
|
|
2280
2354
|
"roadmap",
|
|
2281
2355
|
"feature",
|
|
2282
2356
|
"idea",
|
|
@@ -2308,8 +2382,8 @@ function registerGetHistorySummary(server) {
|
|
|
2308
2382
|
server.registerTool("get_history_summary", {
|
|
2309
2383
|
description: "Get a summary of history events for a date range. Returns counts by entity type, " + "list of changed entities with titles, and total event count. Use this for status " + "report generation instead of get_history to avoid context overflow.",
|
|
2310
2384
|
inputSchema: {
|
|
2311
|
-
startDate:
|
|
2312
|
-
endDate:
|
|
2385
|
+
startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
|
|
2386
|
+
endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format")
|
|
2313
2387
|
}
|
|
2314
2388
|
}, async ({ startDate, endDate }) => {
|
|
2315
2389
|
const client2 = getApiClient();
|
|
@@ -2328,23 +2402,29 @@ function registerCreateStatusUpdate(server) {
|
|
|
2328
2402
|
server.registerTool("create_status_update", {
|
|
2329
2403
|
description: "Create a new status report. Use this after generating the report content from history events.",
|
|
2330
2404
|
inputSchema: {
|
|
2331
|
-
startDate:
|
|
2332
|
-
endDate:
|
|
2333
|
-
content:
|
|
2334
|
-
title:
|
|
2405
|
+
startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period start date in YYYY-MM-DD format"),
|
|
2406
|
+
endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period end date in YYYY-MM-DD format"),
|
|
2407
|
+
content: z11.string().describe("The markdown content of the status report"),
|
|
2408
|
+
title: z11.string().optional().describe("Optional title for the report"),
|
|
2409
|
+
items: z11.array(z11.object({
|
|
2410
|
+
roadmapItemId: z11.string().describe("UUID of the roadmap item"),
|
|
2411
|
+
status: z11.string().describe("Status of the item at report creation time")
|
|
2412
|
+
})).optional().describe("Roadmap items to include in the report snapshot")
|
|
2335
2413
|
}
|
|
2336
2414
|
}, async ({
|
|
2337
2415
|
startDate,
|
|
2338
2416
|
endDate,
|
|
2339
2417
|
content,
|
|
2340
|
-
title
|
|
2418
|
+
title,
|
|
2419
|
+
items
|
|
2341
2420
|
}) => {
|
|
2342
2421
|
const client2 = getApiClient();
|
|
2343
2422
|
const update = await client2.createStatusUpdate({
|
|
2344
2423
|
startDate,
|
|
2345
2424
|
endDate,
|
|
2346
2425
|
content,
|
|
2347
|
-
title
|
|
2426
|
+
title,
|
|
2427
|
+
items
|
|
2348
2428
|
});
|
|
2349
2429
|
return {
|
|
2350
2430
|
content: [
|
|
@@ -2369,18 +2449,18 @@ function registerSaveStories(server) {
|
|
|
2369
2449
|
server.registerTool("save_stories", {
|
|
2370
2450
|
description: "Save epics and stories for a roadmap item. Replaces all existing epics/stories. Use this to set the complete list of epics and stories for a roadmap.",
|
|
2371
2451
|
inputSchema: {
|
|
2372
|
-
roadmapId:
|
|
2373
|
-
epics:
|
|
2374
|
-
title:
|
|
2375
|
-
description:
|
|
2376
|
-
stories:
|
|
2377
|
-
title:
|
|
2378
|
-
description:
|
|
2452
|
+
roadmapId: z11.string().uuid().describe("The UUID of the roadmap item"),
|
|
2453
|
+
epics: z11.array(z11.object({
|
|
2454
|
+
title: z11.string().min(1).describe("Title of the epic"),
|
|
2455
|
+
description: z11.string().nullable().optional().describe("Description of the epic"),
|
|
2456
|
+
stories: z11.array(z11.object({
|
|
2457
|
+
title: z11.string().min(1).describe("Title of the story"),
|
|
2458
|
+
description: z11.string().nullable().optional().describe("Description of the story")
|
|
2379
2459
|
})).optional().describe("Stories within this epic")
|
|
2380
2460
|
})).optional().describe("List of epics with their nested stories"),
|
|
2381
|
-
stories:
|
|
2382
|
-
title:
|
|
2383
|
-
description:
|
|
2461
|
+
stories: z11.array(z11.object({
|
|
2462
|
+
title: z11.string().min(1).describe("Title of the story"),
|
|
2463
|
+
description: z11.string().nullable().optional().describe("Description of the story")
|
|
2384
2464
|
})).optional().describe("List of standalone stories (not part of any epic)")
|
|
2385
2465
|
}
|
|
2386
2466
|
}, async ({
|
|
@@ -2412,10 +2492,10 @@ function registerUploadWireframe(server) {
|
|
|
2412
2492
|
server.registerTool("upload_wireframe", {
|
|
2413
2493
|
description: "Upload an image to a roadmap item's wireframes. Returns a curl command to execute for the upload, then creates the wireframe record. After running the curl command, the wireframe will be visible in the web app.",
|
|
2414
2494
|
inputSchema: {
|
|
2415
|
-
roadmapId:
|
|
2416
|
-
filePath:
|
|
2417
|
-
description:
|
|
2418
|
-
outcomeIds:
|
|
2495
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
2496
|
+
filePath: z11.string().describe("Absolute path to the image file on disk"),
|
|
2497
|
+
description: z11.string().optional().describe("Optional description of the wireframe"),
|
|
2498
|
+
outcomeIds: z11.array(z11.string()).optional().describe("Optional array of PRD outcome IDs this wireframe addresses")
|
|
2419
2499
|
}
|
|
2420
2500
|
}, async ({
|
|
2421
2501
|
roadmapId,
|
|
@@ -2469,9 +2549,9 @@ function registerUpdateWireframe(server) {
|
|
|
2469
2549
|
server.registerTool("update_wireframe", {
|
|
2470
2550
|
description: "Update a wireframe's description or outcome tags.",
|
|
2471
2551
|
inputSchema: {
|
|
2472
|
-
id:
|
|
2473
|
-
description:
|
|
2474
|
-
outcomeIds:
|
|
2552
|
+
id: z11.string().describe("The UUID of the wireframe"),
|
|
2553
|
+
description: z11.string().nullable().optional().describe("New description for the wireframe"),
|
|
2554
|
+
outcomeIds: z11.array(z11.string()).optional().describe("Array of PRD outcome IDs this wireframe addresses (replaces existing)")
|
|
2475
2555
|
}
|
|
2476
2556
|
}, async ({
|
|
2477
2557
|
id,
|
|
@@ -2507,7 +2587,7 @@ function registerDeleteWireframe(server) {
|
|
|
2507
2587
|
server.registerTool("delete_wireframe", {
|
|
2508
2588
|
description: "Delete a wireframe (soft delete).",
|
|
2509
2589
|
inputSchema: {
|
|
2510
|
-
id:
|
|
2590
|
+
id: z11.string().describe("The UUID of the wireframe to delete")
|
|
2511
2591
|
}
|
|
2512
2592
|
}, async ({ id }) => {
|
|
2513
2593
|
const client2 = getApiClient();
|
|
@@ -2526,9 +2606,9 @@ function registerUploadBrainstormMedia(server) {
|
|
|
2526
2606
|
server.registerTool("upload_brainstorm_media", {
|
|
2527
2607
|
description: "Upload an image or video to a roadmap item's brainstorming section. Returns a curl command to execute for the upload.",
|
|
2528
2608
|
inputSchema: {
|
|
2529
|
-
roadmapId:
|
|
2530
|
-
filePath:
|
|
2531
|
-
description:
|
|
2609
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
2610
|
+
filePath: z11.string().describe("Absolute path to the image or video file on disk"),
|
|
2611
|
+
description: z11.string().optional().describe("Optional description of the media")
|
|
2532
2612
|
}
|
|
2533
2613
|
}, async ({
|
|
2534
2614
|
roadmapId,
|
|
@@ -2580,8 +2660,8 @@ function registerUpdateBrainstormMedia(server) {
|
|
|
2580
2660
|
server.registerTool("update_brainstorm_media", {
|
|
2581
2661
|
description: "Update a brainstorm media item's description.",
|
|
2582
2662
|
inputSchema: {
|
|
2583
|
-
id:
|
|
2584
|
-
description:
|
|
2663
|
+
id: z11.string().describe("The UUID of the brainstorm media"),
|
|
2664
|
+
description: z11.string().nullable().describe("New description for the media")
|
|
2585
2665
|
}
|
|
2586
2666
|
}, async ({ id, description }) => {
|
|
2587
2667
|
const client2 = getApiClient();
|
|
@@ -2605,7 +2685,7 @@ function registerDeleteBrainstormMedia(server) {
|
|
|
2605
2685
|
server.registerTool("delete_brainstorm_media", {
|
|
2606
2686
|
description: "Delete a brainstorm media item (soft delete).",
|
|
2607
2687
|
inputSchema: {
|
|
2608
|
-
id:
|
|
2688
|
+
id: z11.string().describe("The UUID of the brainstorm media to delete")
|
|
2609
2689
|
}
|
|
2610
2690
|
}, async ({ id }) => {
|
|
2611
2691
|
const client2 = getApiClient();
|
|
@@ -2624,9 +2704,9 @@ function registerUploadProductDesignMedia(server) {
|
|
|
2624
2704
|
server.registerTool("upload_product_design_media", {
|
|
2625
2705
|
description: "Upload an image or video to a product's design media section. Returns a curl command to execute for the upload.",
|
|
2626
2706
|
inputSchema: {
|
|
2627
|
-
productId:
|
|
2628
|
-
filePath:
|
|
2629
|
-
description:
|
|
2707
|
+
productId: z11.string().describe("The UUID of the product"),
|
|
2708
|
+
filePath: z11.string().describe("Absolute path to the image or video file on disk"),
|
|
2709
|
+
description: z11.string().optional().describe("Optional description of the media")
|
|
2630
2710
|
}
|
|
2631
2711
|
}, async ({
|
|
2632
2712
|
productId,
|
|
@@ -2679,9 +2759,9 @@ function registerUpdateProductDesignMedia(server) {
|
|
|
2679
2759
|
server.registerTool("update_product_design_media", {
|
|
2680
2760
|
description: "Update a product design media item's description.",
|
|
2681
2761
|
inputSchema: {
|
|
2682
|
-
productId:
|
|
2683
|
-
mediaId:
|
|
2684
|
-
description:
|
|
2762
|
+
productId: z11.string().describe("The UUID of the product"),
|
|
2763
|
+
mediaId: z11.string().describe("The UUID of the design media"),
|
|
2764
|
+
description: z11.string().nullable().describe("New description for the media")
|
|
2685
2765
|
}
|
|
2686
2766
|
}, async ({
|
|
2687
2767
|
productId,
|
|
@@ -2709,8 +2789,8 @@ function registerDeleteProductDesignMedia(server) {
|
|
|
2709
2789
|
server.registerTool("delete_product_design_media", {
|
|
2710
2790
|
description: "Delete a product design media item (soft delete).",
|
|
2711
2791
|
inputSchema: {
|
|
2712
|
-
productId:
|
|
2713
|
-
mediaId:
|
|
2792
|
+
productId: z11.string().describe("The UUID of the product"),
|
|
2793
|
+
mediaId: z11.string().describe("The UUID of the design media to delete")
|
|
2714
2794
|
}
|
|
2715
2795
|
}, async ({ productId, mediaId }) => {
|
|
2716
2796
|
const client2 = getApiClient();
|
|
@@ -2732,8 +2812,8 @@ function registerUploadDesignWalkthrough(server) {
|
|
|
2732
2812
|
server.registerTool("upload_design_walkthrough", {
|
|
2733
2813
|
description: "Upload a walkthrough video to a roadmap item's design phase. Returns a curl command to execute for the upload.",
|
|
2734
2814
|
inputSchema: {
|
|
2735
|
-
roadmapId:
|
|
2736
|
-
filePath:
|
|
2815
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
2816
|
+
filePath: z11.string().describe("Absolute path to the video file on disk")
|
|
2737
2817
|
}
|
|
2738
2818
|
}, async ({ roadmapId, filePath }) => {
|
|
2739
2819
|
const client2 = getApiClient();
|
|
@@ -2775,8 +2855,8 @@ function registerUploadReleaseWalkthrough(server) {
|
|
|
2775
2855
|
server.registerTool("upload_release_walkthrough", {
|
|
2776
2856
|
description: "Upload a walkthrough video to a roadmap item's release phase. Returns a curl command to execute for the upload.",
|
|
2777
2857
|
inputSchema: {
|
|
2778
|
-
roadmapId:
|
|
2779
|
-
filePath:
|
|
2858
|
+
roadmapId: z11.string().describe("The UUID of the roadmap item"),
|
|
2859
|
+
filePath: z11.string().describe("Absolute path to the video file on disk")
|
|
2780
2860
|
}
|
|
2781
2861
|
}, async ({ roadmapId, filePath }) => {
|
|
2782
2862
|
const client2 = getApiClient();
|
|
@@ -2814,6 +2894,183 @@ function registerUploadReleaseWalkthrough(server) {
|
|
|
2814
2894
|
};
|
|
2815
2895
|
});
|
|
2816
2896
|
}
|
|
2897
|
+
function getPrototypeContentType(filename) {
|
|
2898
|
+
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
2899
|
+
const types = {
|
|
2900
|
+
html: "text/html",
|
|
2901
|
+
css: "text/css",
|
|
2902
|
+
js: "application/javascript",
|
|
2903
|
+
json: "application/json",
|
|
2904
|
+
png: "image/png",
|
|
2905
|
+
jpg: "image/jpeg",
|
|
2906
|
+
jpeg: "image/jpeg",
|
|
2907
|
+
gif: "image/gif",
|
|
2908
|
+
svg: "image/svg+xml",
|
|
2909
|
+
webp: "image/webp"
|
|
2910
|
+
};
|
|
2911
|
+
return types[ext] || "application/octet-stream";
|
|
2912
|
+
}
|
|
2913
|
+
function registerPublishPrototype(server) {
|
|
2914
|
+
server.registerTool("publish_prototype", {
|
|
2915
|
+
description: "Publish a local prototype folder to a shareable URL. Uploads all files from the folder and returns a time-limited shareable link.",
|
|
2916
|
+
inputSchema: {
|
|
2917
|
+
roadmapId: z11.string().uuid().describe("The UUID of the roadmap item to attach the prototype to"),
|
|
2918
|
+
folderPath: z11.string().describe("Absolute path to the local mockup folder"),
|
|
2919
|
+
entryPoint: z11.string().default("index.html").describe("Main HTML file to open (defaults to index.html)")
|
|
2920
|
+
}
|
|
2921
|
+
}, async ({
|
|
2922
|
+
roadmapId,
|
|
2923
|
+
folderPath,
|
|
2924
|
+
entryPoint
|
|
2925
|
+
}) => {
|
|
2926
|
+
const fs = await import("node:fs/promises");
|
|
2927
|
+
const path = await import("node:path");
|
|
2928
|
+
const client2 = getApiClient();
|
|
2929
|
+
const ignoredNames = new Set([
|
|
2930
|
+
".DS_Store",
|
|
2931
|
+
".git",
|
|
2932
|
+
"node_modules",
|
|
2933
|
+
".env",
|
|
2934
|
+
".gitignore",
|
|
2935
|
+
".npmrc",
|
|
2936
|
+
"Thumbs.db",
|
|
2937
|
+
".idea",
|
|
2938
|
+
".vscode"
|
|
2939
|
+
]);
|
|
2940
|
+
async function scanFolder(dir, base = "") {
|
|
2941
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2942
|
+
const files2 = [];
|
|
2943
|
+
for (const entry of entries) {
|
|
2944
|
+
if (entry.name.startsWith(".") || ignoredNames.has(entry.name)) {
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
const relativePath = base ? `${base}/${entry.name}` : entry.name;
|
|
2948
|
+
const fullPath = path.join(dir, entry.name);
|
|
2949
|
+
if (entry.isDirectory()) {
|
|
2950
|
+
files2.push(...await scanFolder(fullPath, relativePath));
|
|
2951
|
+
} else {
|
|
2952
|
+
files2.push(relativePath);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
return files2;
|
|
2956
|
+
}
|
|
2957
|
+
try {
|
|
2958
|
+
await fs.access(folderPath);
|
|
2959
|
+
} catch {
|
|
2960
|
+
return {
|
|
2961
|
+
content: [
|
|
2962
|
+
{
|
|
2963
|
+
type: "text",
|
|
2964
|
+
text: `Error: Folder not found: ${folderPath}`
|
|
2965
|
+
}
|
|
2966
|
+
]
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2969
|
+
const files = await scanFolder(folderPath);
|
|
2970
|
+
if (files.length === 0) {
|
|
2971
|
+
return {
|
|
2972
|
+
content: [
|
|
2973
|
+
{
|
|
2974
|
+
type: "text",
|
|
2975
|
+
text: `Error: No files found in ${folderPath}`
|
|
2976
|
+
}
|
|
2977
|
+
]
|
|
2978
|
+
};
|
|
2979
|
+
}
|
|
2980
|
+
if (!files.includes(entryPoint)) {
|
|
2981
|
+
return {
|
|
2982
|
+
content: [
|
|
2983
|
+
{
|
|
2984
|
+
type: "text",
|
|
2985
|
+
text: `Error: Entry point "${entryPoint}" not found. Available files: ${files.slice(0, 10).join(", ")}${files.length > 10 ? "..." : ""}`
|
|
2986
|
+
}
|
|
2987
|
+
]
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
const filesWithTypes = files.map((filename) => ({
|
|
2991
|
+
filename,
|
|
2992
|
+
contentType: getPrototypeContentType(filename)
|
|
2993
|
+
}));
|
|
2994
|
+
let uploadData;
|
|
2995
|
+
try {
|
|
2996
|
+
uploadData = await client2.getPrototypeUploadUrls(roadmapId, filesWithTypes);
|
|
2997
|
+
} catch (error) {
|
|
2998
|
+
return {
|
|
2999
|
+
content: [
|
|
3000
|
+
{
|
|
3001
|
+
type: "text",
|
|
3002
|
+
text: `Error getting upload URLs: ${error instanceof Error ? error.message : String(error)}`
|
|
3003
|
+
}
|
|
3004
|
+
]
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
3007
|
+
const uploadUrlMap = new Map(uploadData.files.map((f) => [f.filename, f.uploadUrl]));
|
|
3008
|
+
let uploaded = 0;
|
|
3009
|
+
for (const file of files) {
|
|
3010
|
+
const filePath = path.join(folderPath, file);
|
|
3011
|
+
const fileContent = await fs.readFile(filePath);
|
|
3012
|
+
const uploadUrl = uploadUrlMap.get(file);
|
|
3013
|
+
if (!uploadUrl) {
|
|
3014
|
+
return {
|
|
3015
|
+
content: [
|
|
3016
|
+
{
|
|
3017
|
+
type: "text",
|
|
3018
|
+
text: `Error: No upload URL found for ${file}`
|
|
3019
|
+
}
|
|
3020
|
+
]
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
try {
|
|
3024
|
+
await client2.uploadFile(uploadUrl, fileContent, getPrototypeContentType(file));
|
|
3025
|
+
uploaded++;
|
|
3026
|
+
} catch (error) {
|
|
3027
|
+
return {
|
|
3028
|
+
content: [
|
|
3029
|
+
{
|
|
3030
|
+
type: "text",
|
|
3031
|
+
text: `Error uploading ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
3032
|
+
}
|
|
3033
|
+
]
|
|
3034
|
+
};
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
let prototype;
|
|
3038
|
+
try {
|
|
3039
|
+
prototype = await client2.createPrototype(roadmapId, {
|
|
3040
|
+
token: uploadData.token,
|
|
3041
|
+
fileCount: files.length,
|
|
3042
|
+
entryPoint
|
|
3043
|
+
});
|
|
3044
|
+
} catch (error) {
|
|
3045
|
+
return {
|
|
3046
|
+
content: [
|
|
3047
|
+
{
|
|
3048
|
+
type: "text",
|
|
3049
|
+
text: `Error creating prototype record: ${error instanceof Error ? error.message : String(error)}`
|
|
3050
|
+
}
|
|
3051
|
+
]
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
const expiryDate = new Date(prototype.expiresAt).toLocaleDateString("en-US", {
|
|
3055
|
+
month: "long",
|
|
3056
|
+
day: "numeric",
|
|
3057
|
+
year: "numeric"
|
|
3058
|
+
});
|
|
3059
|
+
return {
|
|
3060
|
+
content: [
|
|
3061
|
+
{
|
|
3062
|
+
type: "text",
|
|
3063
|
+
text: `Published ${uploaded} files!
|
|
3064
|
+
|
|
3065
|
+
Share this link:
|
|
3066
|
+
${prototype.publicUrl}
|
|
3067
|
+
|
|
3068
|
+
Expires: ${expiryDate}`
|
|
3069
|
+
}
|
|
3070
|
+
]
|
|
3071
|
+
};
|
|
3072
|
+
});
|
|
3073
|
+
}
|
|
2817
3074
|
|
|
2818
3075
|
// src/index.ts
|
|
2819
3076
|
async function main() {
|