pptx-viewer-mcp 2.5.8 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp/index.js CHANGED
@@ -1,13 +1,12 @@
1
- #!/usr/bin/env node
2
1
  'use strict';
3
2
 
4
- var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
5
3
  var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
6
4
  var zod = require('zod');
7
- var pptxViewerCore = require('pptx-viewer-core');
5
+ var automation = require('ooxml-core/pptx/automation');
8
6
  var promises = require('fs/promises');
9
7
  var path = require('path');
10
8
 
9
+ // src/mcp/server.ts
11
10
  var GetSlideSchema = zod.z.object({
12
11
  filePath: zod.z.string().describe("Path to the PPTX file"),
13
12
  slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index")
@@ -932,3162 +931,86 @@ var SetOleObjectNameSchema = zod.z.object({
932
931
  elementId: zod.z.string().describe("OLE element ID"),
933
932
  name: zod.z.string().describe("New Object Name (p:oleObj/@name); blank/whitespace clears it")
934
933
  });
935
- function generateElementId() {
936
- return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
937
- }
938
- function generateSlideId() {
939
- return `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
940
- }
941
- function describeElement(el) {
942
- const base = {
943
- id: el.id,
944
- type: el.type,
945
- x: Math.round(el.x),
946
- y: Math.round(el.y),
947
- width: Math.round(el.width),
948
- height: Math.round(el.height)
949
- };
950
- if (el.rotation) {
951
- base.rotation = el.rotation;
952
- }
953
- if (el.hidden) {
954
- base.hidden = true;
955
- }
956
- if (el.opacity !== void 0 && el.opacity !== 1) {
957
- base.opacity = el.opacity;
958
- }
959
- if (pptxViewerCore.hasTextProperties(el)) {
960
- base.text = el.text ?? "";
961
- if (el.textStyle) {
962
- const ts = {};
963
- if (el.textStyle.fontSize) {
964
- ts.fontSize = el.textStyle.fontSize;
965
- }
966
- if (el.textStyle.fontFamily) {
967
- ts.fontFamily = el.textStyle.fontFamily;
968
- }
969
- if (el.textStyle.bold) {
970
- ts.bold = true;
971
- }
972
- if (el.textStyle.italic) {
973
- ts.italic = true;
974
- }
975
- if (el.textStyle.underline) {
976
- ts.underline = el.textStyle.underline;
977
- }
978
- if (el.textStyle.align) {
979
- ts.align = el.textStyle.align;
980
- }
981
- if (el.textStyle.color) {
982
- ts.color = el.textStyle.color;
983
- }
984
- if (Object.keys(ts).length > 0) {
985
- base.textStyle = ts;
986
- }
987
- }
988
- }
989
- if ("shapeType" in el && el.shapeType) {
990
- base.shapeType = el.shapeType;
991
- }
992
- if ("shapeStyle" in el && el.shapeStyle) {
993
- const ss = {};
994
- const style = el.shapeStyle;
995
- if (style.fillColor) {
996
- ss.fillColor = style.fillColor;
997
- }
998
- if (style.strokeColor) {
999
- ss.strokeColor = style.strokeColor;
1000
- }
1001
- if (style.strokeWidth) {
1002
- ss.strokeWidth = style.strokeWidth;
1003
- }
1004
- if (Object.keys(ss).length > 0) {
1005
- base.shapeStyle = ss;
1006
- }
1007
- }
1008
- if (el.type === "image" || el.type === "picture") {
1009
- const img = el;
1010
- if (img.altText) {
1011
- base.altText = img.altText;
1012
- }
1013
- if (img.imagePath) {
1014
- base.imagePath = img.imagePath;
1015
- }
1016
- base.hasImageData = Boolean(img.imageData);
1017
- }
1018
- if (el.type === "table") {
1019
- const tbl = el;
1020
- if (tbl.tableData) {
1021
- base.rowCount = tbl.tableData.rows.length;
1022
- base.columnCount = tbl.tableData.columnWidths.length;
1023
- base.cells = tbl.tableData.rows.map((row) => row.cells.map((cell) => cell.text ?? ""));
1024
- }
1025
- }
1026
- if (el.type === "chart" && el.chartData) {
1027
- base.chartType = pptxViewerCore.resolveDisplayedChartTypeName(el.chartData);
1028
- }
1029
- if (el.type === "group") {
1030
- const grp = el;
1031
- base.childCount = grp.children?.length ?? 0;
1032
- }
1033
- return base;
1034
- }
1035
- function validateSlideIndex(slideIndex, slideCount) {
1036
- if (slideIndex < 0 || slideIndex >= slideCount) {
1037
- return `Slide index ${slideIndex} out of range (0\u2013${slideCount - 1}).`;
1038
- }
1039
- return null;
1040
- }
1041
-
1042
- // src/tools/chart-formatting-tools.ts
1043
- function findChartElement(ctx, slideIndex, elementId) {
1044
- const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
1045
- if (err) {
1046
- throw new Error(err);
1047
- }
1048
- const slide = ctx.pptxData.slides[slideIndex];
1049
- const el = slide.elements.find((e) => e.id === elementId);
1050
- if (!el) {
1051
- throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
1052
- }
1053
- if (el.type !== "chart") {
1054
- throw new Error(`Element '${elementId}' is not a chart.`);
1055
- }
1056
- return el;
1057
- }
1058
- function formatChartDataPoint(ctx, params) {
1059
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
1060
- if (params.clearStyle) {
1061
- pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
1062
- } else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
1063
- pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
1064
- ...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
1065
- ...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
1066
- ...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
1067
- ...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
1068
- });
1069
- }
1070
- if (params.explosion !== void 0) {
1071
- pptxViewerCore.setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
1072
- }
1073
- if (params.marker !== void 0) {
1074
- pptxViewerCore.setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
1075
- }
1076
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1077
- }
1078
- function formatChartDataLabel(ctx, params) {
1079
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
1080
- if (params.remove) {
1081
- pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
1082
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1083
- }
1084
- pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
1085
- ...params.showValue !== void 0 ? { showValue: params.showValue } : {},
1086
- ...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
1087
- ...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
1088
- ...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
1089
- ...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
1090
- ...params.position !== void 0 ? { position: params.position } : {},
1091
- ...params.text !== void 0 ? { text: params.text } : {},
1092
- ...params.spPr !== void 0 ? { spPr: params.spPr } : {},
1093
- ...params.txPr !== void 0 ? { txPr: params.txPr } : {}
1094
- });
1095
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1096
- }
1097
- function formatChartSeries(ctx, params) {
1098
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
1099
- if (params.marker !== void 0) {
1100
- if (params.marker === null) {
1101
- pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, null);
1102
- } else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
1103
- pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, {
1104
- symbol: params.marker.symbol ?? "circle",
1105
- ...params.marker.size !== void 0 ? { size: params.marker.size } : {},
1106
- spPr: {
1107
- ...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
1108
- ...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
1109
- ...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
1110
- ...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
1111
- }
1112
- });
1113
- } else {
1114
- pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, params.marker);
1115
- }
1116
- }
1117
- if (params.trendline !== void 0) {
1118
- pptxViewerCore.setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
1119
- }
1120
- if (params.errorBars !== void 0) {
1121
- pptxViewerCore.setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
1122
- }
1123
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1124
- }
1125
- function setChartHelperLineT(ctx, params) {
1126
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
1127
- pptxViewerCore.setChartHelperLine(chart, params.line, params.style);
1128
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1129
- }
1130
- function setChartColorMapOverrideT(ctx, params) {
1131
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
1132
- pptxViewerCore.setChartColorMapOverride(chart, params.overrides);
1133
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1134
- }
1135
-
1136
- // src/tools/chart-pareto.ts
1137
- function cumulativePercent(values) {
1138
- const total = values.reduce((sum, value) => sum + value, 0);
1139
- if (total === 0) {
1140
- return values.map(() => 0);
1141
- }
1142
- let running = 0;
1143
- return values.map((value) => {
1144
- running += value;
1145
- return Math.round(running / total * 1e4) / 100;
1146
- });
1147
- }
1148
- function applyParetoChartTypeAlias(chart, requestedType) {
1149
- if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
1150
- return;
1151
- }
1152
- const data = chart.chartData;
1153
- data.chartType = "histogram";
1154
- const [frequency] = data.series;
1155
- if (!frequency) {
1156
- return;
1157
- }
1158
- frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
1159
- const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
1160
- if (!hasParetoLine) {
1161
- data.series.push({
1162
- name: "Cumulative %",
1163
- values: cumulativePercent(frequency.values),
1164
- histogramOptions: { layout: "pareto" }
1165
- });
1166
- }
1167
- }
1168
-
1169
- // src/tools/chart-tools.ts
1170
- function updateChart(ctx, params) {
1171
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1172
- if (err) {
1173
- throw new Error(err);
1174
- }
1175
- const slide = ctx.pptxData.slides[params.slideIndex];
1176
- const el = slide.elements.find((e) => e.id === params.elementId);
1177
- if (!el) {
1178
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1179
- }
1180
- if (el.type !== "chart") {
1181
- throw new Error(`Element '${params.elementId}' is not a chart.`);
1182
- }
1183
- const chart = el;
1184
- if (params.chartType) {
1185
- pptxViewerCore.setChartType(chart, params.chartType);
1186
- applyParetoChartTypeAlias(chart, params.chartType);
1187
- }
1188
- if (params.title !== void 0) {
1189
- pptxViewerCore.setChartTitle(chart, params.title);
1190
- }
1191
- if (params.grouping) {
1192
- pptxViewerCore.setChartGrouping(chart, params.grouping);
1193
- }
1194
- if (params.legend) {
1195
- pptxViewerCore.setChartLegend(chart, {
1196
- show: params.legend.show,
1197
- position: params.legend.position
1198
- });
1199
- }
1200
- if (params.dataLabels) {
1201
- pptxViewerCore.setChartDataLabels(chart, params.dataLabels);
1202
- }
1203
- if (params.axis) {
1204
- pptxViewerCore.setChartAxis(chart, params.axis.type, params.axis.edit);
1205
- }
1206
- if (params.categories) {
1207
- pptxViewerCore.setChartCategories(chart, params.categories);
1208
- }
1209
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1210
- }
1211
- function addChartSeriesT(ctx, params) {
1212
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1213
- if (err) {
1214
- throw new Error(err);
1215
- }
1216
- const slide = ctx.pptxData.slides[params.slideIndex];
1217
- const el = slide.elements.find((e) => e.id === params.elementId);
1218
- if (!el) {
1219
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1220
- }
1221
- if (el.type !== "chart") {
1222
- throw new Error(`Element '${params.elementId}' is not a chart.`);
1223
- }
1224
- const chart = el;
1225
- pptxViewerCore.addChartSeries(chart, { name: params.name, values: params.values, color: params.color });
1226
- const seriesCount = chart.chartData?.series?.length ?? 0;
1227
- return {
1228
- pptxData: ctx.pptxData,
1229
- dirty: true,
1230
- result: { elementId: params.elementId, seriesCount }
1231
- };
1232
- }
1233
- function removeChartSeriesT(ctx, params) {
1234
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1235
- if (err) {
1236
- throw new Error(err);
1237
- }
1238
- const slide = ctx.pptxData.slides[params.slideIndex];
1239
- const el = slide.elements.find((e) => e.id === params.elementId);
1240
- if (!el) {
1241
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1242
- }
1243
- if (el.type !== "chart") {
1244
- throw new Error(`Element '${params.elementId}' is not a chart.`);
1245
- }
1246
- const chart = el;
1247
- pptxViewerCore.removeChartSeries(chart, params.seriesIndex);
1248
- const seriesCount = chart.chartData?.series?.length ?? 0;
1249
- return {
1250
- pptxData: ctx.pptxData,
1251
- dirty: true,
1252
- result: { elementId: params.elementId, seriesCount }
1253
- };
1254
- }
1255
- function updateChartSeriesData(ctx, params) {
1256
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1257
- if (err) {
1258
- throw new Error(err);
1259
- }
1260
- const slide = ctx.pptxData.slides[params.slideIndex];
1261
- const el = slide.elements.find((e) => e.id === params.elementId);
1262
- if (!el) {
1263
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1264
- }
1265
- if (el.type !== "chart") {
1266
- throw new Error(`Element '${params.elementId}' is not a chart.`);
1267
- }
1268
- const chart = el;
1269
- pptxViewerCore.updateChartSeriesValues(chart, params.seriesIndex, params.values);
1270
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1271
- }
1272
- function createChart(ctx, params) {
1273
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1274
- if (err) {
1275
- throw new Error(err);
1276
- }
1277
- const builder = pptxViewerCore.ChartBuilder.create(
1278
- params.chartType
1279
- );
1280
- builder.position(params.x ?? 100, params.y ?? 100);
1281
- builder.size(params.width ?? 500, params.height ?? 350);
1282
- if (params.title) {
1283
- builder.title(params.title);
1284
- }
1285
- if (params.categories) {
1286
- builder.categories(params.categories);
1287
- }
1288
- if (params.series) {
1289
- for (const s of params.series) {
1290
- builder.addSeries(s.name, s.values, s.color);
1291
- }
1292
- }
1293
- if (params.legend) {
1294
- builder.legend(
1295
- params.legend.show,
1296
- params.legend.position
1297
- );
1298
- }
1299
- const chart = builder.build();
1300
- applyParetoChartTypeAlias(chart, params.chartType);
1301
- const slide = ctx.pptxData.slides[params.slideIndex];
1302
- slide.elements.push(chart);
1303
- return {
1304
- pptxData: ctx.pptxData,
1305
- dirty: true,
1306
- result: { elementId: chart.id, slideIndex: params.slideIndex }
1307
- };
1308
- }
1309
- function findChartElement2(ctx, slideIndex, elementId) {
1310
- const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
1311
- if (err) {
1312
- throw new Error(err);
1313
- }
1314
- const slide = ctx.pptxData.slides[slideIndex];
1315
- const el = slide.elements.find((e) => e.id === elementId);
1316
- if (!el) {
1317
- throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
1318
- }
1319
- if (el.type !== "chart") {
1320
- throw new Error(`Element '${elementId}' is not a chart.`);
1321
- }
1322
- return el;
1323
- }
1324
- function buildShape(input) {
1325
- return {
1326
- kind: input.kind ?? "sp",
1327
- anchor: input.anchor ?? "rel",
1328
- from: input.from,
1329
- ...input.to ? { to: input.to } : {},
1330
- ...input.ext ? { ext: input.ext } : {},
1331
- ...input.prst ? { prst: input.prst } : {},
1332
- ...input.fill ? { fill: input.fill } : {},
1333
- ...input.stroke ? { stroke: input.stroke } : {},
1334
- ...input.strokeWidth !== void 0 ? { strokeWidth: input.strokeWidth } : {},
1335
- ...input.text ? { paragraphs: [{ text: input.text, align: "ctr" }] } : {}
1336
- };
1337
- }
1338
- function listChartUserShapesT(ctx, params) {
1339
- const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1340
- return { pptxData: ctx.pptxData, dirty: false, result: { shapes: pptxViewerCore.listChartUserShapes(chart) } };
1341
- }
1342
- function addChartUserShapeT(ctx, params) {
1343
- const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1344
- pptxViewerCore.addChartUserShape(chart, buildShape(params.shape));
1345
- const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
1346
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
1347
- }
1348
- function updateChartUserShapeT(ctx, params) {
1349
- const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1350
- const patch = {
1351
- ...params.patch.kind ? { kind: params.patch.kind } : {},
1352
- ...params.patch.anchor ? { anchor: params.patch.anchor } : {},
1353
- ...params.patch.from ? { from: params.patch.from } : {},
1354
- ...params.patch.to ? { to: params.patch.to } : {},
1355
- ...params.patch.ext ? { ext: params.patch.ext } : {},
1356
- ...params.patch.prst ? { prst: params.patch.prst } : {},
1357
- ...params.patch.fill ? { fill: params.patch.fill } : {},
1358
- ...params.patch.stroke ? { stroke: params.patch.stroke } : {},
1359
- ...params.patch.strokeWidth !== void 0 ? { strokeWidth: params.patch.strokeWidth } : {},
1360
- ...params.patch.text !== void 0 ? { paragraphs: [{ text: params.patch.text, align: "ctr" }] } : {}
1361
- };
1362
- pptxViewerCore.updateChartUserShape(chart, params.index, patch);
1363
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1364
- }
1365
- function removeChartUserShapeT(ctx, params) {
1366
- const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1367
- pptxViewerCore.removeChartUserShape(chart, params.index);
1368
- return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1369
- }
1370
-
1371
- // src/tools/text-editing.ts
1372
- function editRange(segments, start, end, replacement) {
1373
- let offset = 0;
1374
- let inserted = false;
1375
- for (const segment of segments) {
1376
- const text = segment.text;
1377
- const next = offset + text.length;
1378
- if (!segment.bulletInfo?.ownedByParagraph && next > start && offset < end) {
1379
- const from = Math.max(0, start - offset);
1380
- const to = Math.min(text.length, end - offset);
1381
- segment.text = text.slice(0, from) + (inserted ? "" : replacement) + text.slice(to);
1382
- inserted = true;
1383
- } else if (!inserted && start === end && offset <= start && next >= start && !segment.bulletInfo?.ownedByParagraph) {
1384
- const at = start - offset;
1385
- segment.text = text.slice(0, at) + replacement + text.slice(at);
1386
- inserted = true;
1387
- }
1388
- offset = next;
1389
- }
1390
- if (!inserted && replacement) {
1391
- segments.push({ text: replacement, style: {} });
1392
- }
1393
- }
1394
- function changedRange(before, text) {
1395
- let start = 0;
1396
- while (start < before.length && start < text.length && before[start] === text[start]) {
1397
- start++;
1398
- }
1399
- let suffix = 0;
1400
- while (suffix < before.length - start && suffix < text.length - start && before[before.length - suffix - 1] === text[text.length - suffix - 1]) {
1401
- suffix++;
1402
- }
1403
- return {
1404
- start,
1405
- end: before.length - suffix,
1406
- replacement: text.slice(start, text.length - suffix)
1407
- };
1408
- }
1409
- function setElementText(element, text) {
1410
- const segments = element.textSegments;
1411
- if (segments?.length) {
1412
- const before = segments.map((segment) => segment.text).join("");
1413
- const oldLines = before.split("\n");
1414
- const newLines = text.split("\n");
1415
- if (oldLines.length === newLines.length) {
1416
- let offset = before.length;
1417
- for (let index = oldLines.length - 1; index >= 0; index--) {
1418
- const line = oldLines[index];
1419
- offset -= line.length;
1420
- const edit = changedRange(line, newLines[index]);
1421
- editRange(segments, offset + edit.start, offset + edit.end, edit.replacement);
1422
- offset--;
1423
- }
1424
- } else {
1425
- const edit = changedRange(before, text);
1426
- editRange(segments, edit.start, edit.end, edit.replacement);
1427
- }
1428
- element.text = segments.map((segment) => segment.text).join("");
1429
- } else {
1430
- element.text = text;
1431
- }
1432
- }
1433
- function replaceElementText(element, regex, replacement) {
1434
- const before = element.text ?? element.textSegments?.map((segment) => segment.text).join("") ?? "";
1435
- const matches = Array.from(before.matchAll(regex));
1436
- if (before.replace(regex, replacement) === before) {
1437
- return 0;
1438
- }
1439
- if (!element.textSegments?.length) {
1440
- element.text = before.replace(regex, replacement);
1441
- return matches.length;
1442
- }
1443
- for (const match of matches.reverse()) {
1444
- const start = match.index;
1445
- const end = start + match[0].length;
1446
- const single = new RegExp(regex.source, `${regex.flags.replace("g", "")}y`);
1447
- single.lastIndex = start;
1448
- const after = before.replace(single, replacement);
1449
- editRange(
1450
- element.textSegments,
1451
- start,
1452
- end,
1453
- after.slice(start, after.length - (before.length - end))
1454
- );
1455
- }
1456
- element.text = element.textSegments.map((segment) => segment.text).join("");
1457
- return matches.length;
1458
- }
1459
-
1460
- // src/tools/content-tools.ts
1461
- var MAX_REGEX_LEN = 200;
1462
- function hasNestedUnboundedQuantifier(pattern) {
1463
- return /\([^)]*[+*]\)[+*]/u.test(pattern);
1464
- }
1465
- function buildSearchRegex(query, useRegex, caseSensitive) {
1466
- if (useRegex) {
1467
- if (query.length > MAX_REGEX_LEN) {
1468
- return null;
1469
- }
1470
- if (hasNestedUnboundedQuantifier(query)) {
1471
- return null;
1472
- }
1473
- }
1474
- const pattern = useRegex ? query : query.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
1475
- const flags = caseSensitive ? "g" : "gi";
1476
- try {
1477
- return new RegExp(pattern, flags);
1478
- } catch {
1479
- return null;
1480
- }
1481
- }
1482
- function findText(ctx, params) {
1483
- const regex = buildSearchRegex(
1484
- params.query,
1485
- params.useRegex === true,
1486
- params.caseSensitive === true
1487
- );
1488
- if (!regex) {
1489
- return {
1490
- pptxData: ctx.pptxData,
1491
- dirty: false,
1492
- result: { query: params.query, matchCount: 0, matches: [] }
1493
- };
1494
- }
1495
- const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
1496
- const matches = [];
1497
- for (const si of targetIndexes) {
1498
- const err = validateSlideIndex(si, ctx.pptxData.slides.length);
1499
- if (err) {
1500
- throw new Error(err);
1501
- }
1502
- const slide = ctx.pptxData.slides[si];
1503
- for (const el of slide.elements) {
1504
- if (pptxViewerCore.hasTextProperties(el)) {
1505
- const textEl = el;
1506
- if (textEl.text) {
1507
- const localMatches = Array.from(textEl.text.matchAll(regex));
1508
- for (const m of localMatches) {
1509
- matches.push({
1510
- slideIndex: si,
1511
- elementId: el.id,
1512
- elementType: el.type,
1513
- matchedText: m[0],
1514
- context: textEl.text.slice(
1515
- Math.max(0, (m.index ?? 0) - 20),
1516
- (m.index ?? 0) + m[0].length + 20
1517
- )
1518
- });
1519
- }
1520
- }
1521
- }
1522
- if (el.type === "table") {
1523
- const tbl = el;
1524
- if (tbl.tableData) {
1525
- for (const row of tbl.tableData.rows) {
1526
- for (const cell of row.cells) {
1527
- if (cell.text) {
1528
- const localMatches = Array.from(cell.text.matchAll(regex));
1529
- for (const m of localMatches) {
1530
- matches.push({
1531
- slideIndex: si,
1532
- elementId: el.id,
1533
- elementType: "table-cell",
1534
- matchedText: m[0],
1535
- context: cell.text.slice(
1536
- Math.max(0, (m.index ?? 0) - 20),
1537
- (m.index ?? 0) + m[0].length + 20
1538
- )
1539
- });
1540
- }
1541
- }
1542
- }
1543
- }
1544
- }
1545
- }
1546
- }
1547
- if (slide.notes) {
1548
- const noteMatches = Array.from(slide.notes.matchAll(regex));
1549
- for (const m of noteMatches) {
1550
- matches.push({
1551
- slideIndex: si,
1552
- elementId: "notes",
1553
- elementType: "notes",
1554
- matchedText: m[0],
1555
- context: slide.notes.slice(
1556
- Math.max(0, (m.index ?? 0) - 20),
1557
- (m.index ?? 0) + m[0].length + 20
1558
- )
1559
- });
1560
- }
1561
- }
1562
- }
1563
- return {
1564
- pptxData: ctx.pptxData,
1565
- dirty: false,
1566
- result: {
1567
- query: params.query,
1568
- matchCount: matches.length,
1569
- matches
1570
- }
1571
- };
1572
- }
1573
- function replaceText(ctx, params) {
1574
- const regex = buildSearchRegex(
1575
- params.query,
1576
- params.useRegex === true,
1577
- params.caseSensitive === true
1578
- );
1579
- if (!regex) {
1580
- return {
1581
- pptxData: ctx.pptxData,
1582
- dirty: false,
1583
- result: { query: params.query, replacement: params.replacement, replacementCount: 0 }
1584
- };
1585
- }
1586
- const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
1587
- let count = 0;
1588
- for (const si of targetIndexes) {
1589
- const err = validateSlideIndex(si, ctx.pptxData.slides.length);
1590
- if (err) {
1591
- throw new Error(err);
1592
- }
1593
- const slide = ctx.pptxData.slides[si];
1594
- for (const el of slide.elements) {
1595
- if (pptxViewerCore.hasTextProperties(el)) {
1596
- const textEl = el;
1597
- if (textEl.text) {
1598
- const before = textEl.text;
1599
- const after = before.replace(regex, params.replacement);
1600
- if (after !== before) {
1601
- const matchCount = Array.from(before.matchAll(regex)).length;
1602
- count += matchCount;
1603
- replaceElementText(textEl, regex, params.replacement);
1604
- }
1605
- }
1606
- }
1607
- if (el.type === "table") {
1608
- const tbl = el;
1609
- if (tbl.tableData) {
1610
- for (const row of tbl.tableData.rows) {
1611
- for (const cell of row.cells) {
1612
- if (cell.text) {
1613
- const before = cell.text;
1614
- const after = before.replace(regex, params.replacement);
1615
- if (after !== before) {
1616
- count += Array.from(before.matchAll(regex)).length;
1617
- cell.text = after;
1618
- }
1619
- }
1620
- }
1621
- }
1622
- }
1623
- }
1624
- }
1625
- if (slide.notes) {
1626
- const before = slide.notes;
1627
- const after = before.replace(regex, params.replacement);
1628
- if (after !== before) {
1629
- count += Array.from(before.matchAll(regex)).length;
1630
- slide.notes = after;
1631
- }
1632
- }
1633
- }
1634
- return {
1635
- pptxData: ctx.pptxData,
1636
- dirty: count > 0,
1637
- result: {
1638
- query: params.query,
1639
- replacement: params.replacement,
1640
- replacementCount: count
1641
- }
1642
- };
1643
- }
1644
- function manageComments(ctx, params) {
1645
- switch (params.action) {
1646
- case "list": {
1647
- const all = [];
1648
- for (let si = 0; si < ctx.pptxData.slides.length; si++) {
1649
- if (params.slideIndex !== void 0 && si !== params.slideIndex) {
1650
- continue;
1651
- }
1652
- const slide = ctx.pptxData.slides[si];
1653
- for (const c of slide.comments ?? []) {
1654
- if (!params.includeResolved && c.resolved) {
1655
- continue;
1656
- }
1657
- all.push({
1658
- id: c.id,
1659
- slideIndex: si,
1660
- text: c.text,
1661
- author: c.author,
1662
- createdAt: c.createdAt,
1663
- resolved: c.resolved
1664
- });
1665
- }
1666
- }
1667
- return {
1668
- pptxData: ctx.pptxData,
1669
- dirty: false,
1670
- result: { action: "list", comments: all, count: all.length }
1671
- };
1672
- }
1673
- case "add": {
1674
- if (params.slideIndex === void 0) {
1675
- throw new Error("slideIndex is required for add action.");
1676
- }
1677
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1678
- if (err) {
1679
- throw new Error(err);
1680
- }
1681
- if (!params.text) {
1682
- throw new Error("text is required for add action.");
1683
- }
1684
- const slide = ctx.pptxData.slides[params.slideIndex];
1685
- if (!slide.comments) {
1686
- slide.comments = [];
1687
- }
1688
- const newId = `comment-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1689
- slide.comments.push({
1690
- id: newId,
1691
- text: params.text,
1692
- author: params.author,
1693
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1694
- resolved: false
1695
- });
1696
- return {
1697
- pptxData: ctx.pptxData,
1698
- dirty: true,
1699
- result: { action: "add", commentId: newId }
1700
- };
1701
- }
1702
- case "delete": {
1703
- if (!params.commentId) {
1704
- throw new Error("commentId is required for delete action.");
1705
- }
1706
- let deleted = false;
1707
- for (const slide of ctx.pptxData.slides) {
1708
- if (!slide.comments) {
1709
- continue;
1710
- }
1711
- const before = slide.comments.length;
1712
- slide.comments = slide.comments.filter((c) => c.id !== params.commentId);
1713
- if (slide.comments.length < before) {
1714
- deleted = true;
1715
- break;
1716
- }
1717
- }
1718
- if (!deleted) {
1719
- throw new Error(`Comment '${params.commentId}' not found.`);
1720
- }
1721
- return {
1722
- pptxData: ctx.pptxData,
1723
- dirty: true,
1724
- result: { action: "delete", commentId: params.commentId }
1725
- };
1726
- }
1727
- case "resolve": {
1728
- if (!params.commentId) {
1729
- throw new Error("commentId is required for resolve action.");
1730
- }
1731
- let found = false;
1732
- for (const slide of ctx.pptxData.slides) {
1733
- const comment = slide.comments?.find((c) => c.id === params.commentId);
1734
- if (comment) {
1735
- comment.resolved = params.resolved !== false;
1736
- found = true;
1737
- break;
1738
- }
1739
- }
1740
- if (!found) {
1741
- throw new Error(`Comment '${params.commentId}' not found.`);
1742
- }
1743
- return {
1744
- pptxData: ctx.pptxData,
1745
- dirty: true,
1746
- result: { action: "resolve", commentId: params.commentId }
1747
- };
1748
- }
1749
- default: {
1750
- throw new Error(`Unknown action: ${String(params.action)}`);
1751
- }
1752
- }
1753
- }
1754
- async function convertToMarkdown(ctx, params) {
1755
- const options = {
1756
- mediaFolderName: params.mediaFolderName ?? "media",
1757
- includeMetadata: params.includeMetadata !== false,
1758
- slideRange: params.slideRange,
1759
- includeSpeakerNotes: params.includeSpeakerNotes !== false,
1760
- semanticMode: params.semanticMode === true,
1761
- sourceName: params.sourceName ?? "unknown"
1762
- };
1763
- const outputDir = params.outputDir ?? ".";
1764
- const safeOutputDir = params.scopeOutputDir ? params.scopeOutputDir(outputDir, params.rootDir) : outputDir;
1765
- const converter = new pptxViewerCore.PptxMarkdownConverter(safeOutputDir, options);
1766
- const markdown = await converter.convert(ctx.pptxData);
1767
- return {
1768
- pptxData: ctx.pptxData,
1769
- dirty: false,
1770
- result: {
1771
- markdown,
1772
- slidesConverted: converter.slidesConverted,
1773
- totalSlides: converter.presentationSlides,
1774
- imagesExtracted: converter.imagesExtracted
1775
- }
1776
- };
1777
- }
1778
- var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
1779
- var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1780
- "table",
1781
- "chart",
1782
- "smartArt",
1783
- "ole",
1784
- "media",
1785
- "text",
1786
- "shape",
1787
- "connector"
1788
- ]);
1789
- function applyElementAltText(el, altText) {
1790
- if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
1791
- throw new Error(
1792
- `Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
1793
- );
1794
- }
1795
- el.altText = altText;
1796
- }
1797
- function applyElementTitle(el, title) {
1798
- if (!TITLE_ELEMENT_TYPES.has(el.type)) {
1799
- throw new Error(
1800
- `Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
1801
- );
1802
- }
1803
- el.title = title;
1804
- }
1805
- function updateElementStyle(ctx, params) {
1806
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1807
- if (err) {
1808
- throw new Error(err);
1809
- }
1810
- const slide = ctx.pptxData.slides[params.slideIndex];
1811
- const el = slide.elements.find((e) => e.id === params.elementId);
1812
- if (!el) {
1813
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1814
- }
1815
- if ("shapeStyle" in el) {
1816
- if (!el.shapeStyle) {
1817
- el.shapeStyle = {};
1818
- }
1819
- const ss = el.shapeStyle;
1820
- if (params.fillThemeColor !== void 0) {
1821
- ss.fillColorRef = params.fillThemeColor;
1822
- const resolved = pptxViewerCore.resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
1823
- if (params.fillColor !== void 0) {
1824
- ss.fillColor = params.fillColor;
1825
- } else if (resolved) {
1826
- ss.fillColor = resolved;
1827
- }
1828
- } else if (params.fillColor !== void 0) {
1829
- ss.fillColor = params.fillColor;
1830
- ss.fillColorRef = void 0;
1831
- }
1832
- if (params.fillMode !== void 0) {
1833
- ss.fillMode = params.fillMode;
1834
- }
1835
- if (params.fillGradientStops !== void 0) {
1836
- ss.fillGradientStops = params.fillGradientStops;
1837
- }
1838
- if (params.fillGradientAngle !== void 0) {
1839
- ss.fillGradientAngle = params.fillGradientAngle;
1840
- }
1841
- if (params.fillGradientType !== void 0) {
1842
- ss.fillGradientType = params.fillGradientType;
1843
- }
1844
- if (params.fillOpacity !== void 0) {
1845
- ss.fillOpacity = params.fillOpacity;
1846
- }
1847
- if (params.strokeThemeColor !== void 0) {
1848
- ss.strokeColorRef = params.strokeThemeColor;
1849
- const resolved = pptxViewerCore.resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
1850
- if (params.strokeColor !== void 0) {
1851
- ss.strokeColor = params.strokeColor;
1852
- } else if (resolved) {
1853
- ss.strokeColor = resolved;
1854
- }
1855
- } else if (params.strokeColor !== void 0) {
1856
- ss.strokeColor = params.strokeColor;
1857
- ss.strokeColorRef = void 0;
1858
- }
1859
- if (params.strokeWidth !== void 0) {
1860
- ss.strokeWidth = params.strokeWidth;
1861
- }
1862
- if (params.strokeDash !== void 0) {
1863
- ss.strokeDash = params.strokeDash;
1864
- }
1865
- if (params.strokeOpacity !== void 0) {
1866
- ss.strokeOpacity = params.strokeOpacity;
1867
- }
1868
- if (params.shadowColor !== void 0) {
1869
- ss.shadowColor = params.shadowColor;
1870
- }
1871
- if (params.shadowBlur !== void 0) {
1872
- ss.shadowBlur = params.shadowBlur;
1873
- }
1874
- if (params.shadowOffsetX !== void 0) {
1875
- ss.shadowOffsetX = params.shadowOffsetX;
1876
- }
1877
- if (params.shadowOffsetY !== void 0) {
1878
- ss.shadowOffsetY = params.shadowOffsetY;
1879
- }
1880
- if (params.shadowOpacity !== void 0) {
1881
- ss.shadowOpacity = params.shadowOpacity;
1882
- }
1883
- if (params.glowColor !== void 0) {
1884
- ss.glowColor = params.glowColor;
1885
- }
1886
- if (params.glowRadius !== void 0) {
1887
- ss.glowRadius = params.glowRadius;
1888
- }
1889
- if (params.glowOpacity !== void 0) {
1890
- ss.glowOpacity = params.glowOpacity;
1891
- }
1892
- if (params.softEdgeRadius !== void 0) {
1893
- ss.softEdgeRadius = params.softEdgeRadius;
1894
- }
1895
- }
1896
- if (params.altText !== void 0) {
1897
- applyElementAltText(el, params.altText);
1898
- }
1899
- if (params.title !== void 0) {
1900
- applyElementTitle(el, params.title);
1901
- }
1902
- if (el.type === "image" || el.type === "picture") {
1903
- const img = el;
1904
- if (params.cropLeft !== void 0) {
1905
- img.cropLeft = params.cropLeft;
1906
- }
1907
- if (params.cropTop !== void 0) {
1908
- img.cropTop = params.cropTop;
1909
- }
1910
- if (params.cropRight !== void 0) {
1911
- img.cropRight = params.cropRight;
1912
- }
1913
- if (params.cropBottom !== void 0) {
1914
- img.cropBottom = params.cropBottom;
1915
- }
1916
- if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
1917
- if (!img.imageEffects) {
1918
- img.imageEffects = {};
1919
- }
1920
- if (params.brightness !== void 0) {
1921
- img.imageEffects.brightness = params.brightness;
1922
- }
1923
- if (params.contrast !== void 0) {
1924
- img.imageEffects.contrast = params.contrast;
1925
- }
1926
- if (params.grayscale !== void 0) {
1927
- img.imageEffects.grayscale = params.grayscale;
1928
- }
1929
- }
1930
- }
1931
- return {
1932
- pptxData: ctx.pptxData,
1933
- dirty: true,
1934
- result: { elementId: params.elementId }
1935
- };
1936
- }
1937
- function runAccessibilityCheck(ctx) {
1938
- const issues = [];
1939
- for (let si = 0; si < ctx.pptxData.slides.length; si++) {
1940
- const slide = ctx.pptxData.slides[si];
1941
- let slideHasText = false;
1942
- for (const el of slide.elements) {
1943
- if (el.type === "image" || el.type === "picture") {
1944
- const img = el;
1945
- if (!img.altText) {
1946
- issues.push({
1947
- slideIndex: si,
1948
- elementId: el.id,
1949
- severity: "error",
1950
- message: `Image element '${el.id}' has no alt text.`
1951
- });
1952
- }
1953
- }
1954
- if (pptxViewerCore.hasTextProperties(el)) {
1955
- const textEl = el;
1956
- slideHasText = true;
1957
- if (!textEl.text || textEl.text.trim() === "") {
1958
- issues.push({
1959
- slideIndex: si,
1960
- elementId: el.id,
1961
- severity: "info",
1962
- message: `Text element '${el.id}' is empty.`
1963
- });
1964
- }
1965
- const fs = textEl.textStyle?.fontSize;
1966
- if (fs !== void 0 && fs < 10) {
1967
- issues.push({
1968
- slideIndex: si,
1969
- elementId: el.id,
1970
- severity: "warning",
1971
- message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
1972
- });
1973
- }
1974
- const textColor = textEl.textStyle?.color?.toLowerCase();
1975
- const bgColor = slide.backgroundColor?.toLowerCase();
1976
- if (textColor && bgColor && textColor === bgColor) {
1977
- issues.push({
1978
- slideIndex: si,
1979
- elementId: el.id,
1980
- severity: "error",
1981
- message: `Text element '${el.id}' has same color as slide background (${textColor}).`
1982
- });
1983
- }
1984
- }
1985
- }
1986
- if (!slideHasText) {
1987
- issues.push({
1988
- slideIndex: si,
1989
- severity: "warning",
1990
- message: `Slide ${si + 1} contains no text elements.`
1991
- });
1992
- }
1993
- }
1994
- const errorCount = issues.filter((i) => i.severity === "error").length;
1995
- const warningCount = issues.filter((i) => i.severity === "warning").length;
1996
- const infoCount = issues.filter((i) => i.severity === "info").length;
1997
- return {
1998
- pptxData: ctx.pptxData,
1999
- dirty: false,
2000
- result: {
2001
- slideCount: ctx.pptxData.slides.length,
2002
- totalIssues: issues.length,
2003
- errorCount,
2004
- warningCount,
2005
- infoCount,
2006
- issues
2007
- }
2008
- };
2009
- }
2010
-
2011
- // src/tools/element-tools.ts
2012
- function addElement(ctx, params) {
2013
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2014
- if (err) {
2015
- throw new Error(err);
2016
- }
2017
- const slide = ctx.pptxData.slides[params.slideIndex];
2018
- const id = generateElementId();
2019
- const x = params.x ?? 100;
2020
- const y = params.y ?? 100;
2021
- const width = params.width ?? 300;
2022
- const height = params.height ?? 60;
2023
- switch (params.type) {
2024
- case "text": {
2025
- const el = {
2026
- id,
2027
- type: "text",
2028
- x,
2029
- y,
2030
- width,
2031
- height,
2032
- text: params.text ?? "",
2033
- textStyle: {
2034
- fontSize: params.fontSize,
2035
- fontFamily: params.fontFamily,
2036
- color: params.fontColor,
2037
- bold: params.bold,
2038
- italic: params.italic,
2039
- underline: params.underline,
2040
- align: params.alignment
2041
- },
2042
- textSegments: [
2043
- {
2044
- text: params.text ?? "",
2045
- style: {
2046
- fontSize: params.fontSize,
2047
- fontFamily: params.fontFamily,
2048
- color: params.fontColor,
2049
- bold: params.bold,
2050
- italic: params.italic,
2051
- underline: params.underline
2052
- }
2053
- }
2054
- ]
2055
- };
2056
- slide.elements.push(el);
2057
- break;
2058
- }
2059
- case "shape": {
2060
- const el = {
2061
- id,
2062
- type: "shape",
2063
- x,
2064
- y,
2065
- width,
2066
- height,
2067
- shapeType: params.shapeType ?? "rect",
2068
- text: params.text,
2069
- textStyle: params.text ? {
2070
- fontSize: params.fontSize,
2071
- fontFamily: params.fontFamily,
2072
- color: params.fontColor,
2073
- bold: params.bold,
2074
- italic: params.italic,
2075
- align: params.alignment
2076
- } : void 0,
2077
- shapeStyle: {
2078
- fillColor: params.fillColor,
2079
- strokeColor: params.strokeColor,
2080
- strokeWidth: params.strokeWidth
2081
- }
2082
- };
2083
- slide.elements.push(el);
2084
- break;
2085
- }
2086
- case "image": {
2087
- const el = {
2088
- id,
2089
- type: "image",
2090
- x,
2091
- y,
2092
- width,
2093
- height,
2094
- imageData: params.imageData,
2095
- altText: params.altText
2096
- };
2097
- slide.elements.push(el);
2098
- break;
2099
- }
2100
- case "table": {
2101
- const rowCount = params.rows ?? 2;
2102
- const colCount = params.columns ?? 2;
2103
- const colWidth = 1 / colCount;
2104
- const tableRows = Array.from({ length: rowCount }, (_, r) => ({
2105
- height: 40,
2106
- cells: Array.from({ length: colCount }, (__, c) => ({
2107
- text: params.cellData?.[r]?.[c] ?? ""
2108
- }))
2109
- }));
2110
- const tableEl = {
2111
- id,
2112
- type: "table",
2113
- x,
2114
- y,
2115
- width,
2116
- height: params.height ?? rowCount * 40,
2117
- tableData: {
2118
- rows: tableRows,
2119
- columnWidths: Array.from({ length: colCount }, () => colWidth),
2120
- firstRowHeader: params.headerRow ?? false
2121
- }
2122
- };
2123
- slide.elements.push(tableEl);
2124
- break;
2125
- }
2126
- case "connector": {
2127
- const el = {
2128
- id,
2129
- type: "connector",
2130
- x,
2131
- y,
2132
- width,
2133
- height,
2134
- shapeStyle: {
2135
- strokeColor: params.strokeColor ?? "#000000",
2136
- strokeWidth: params.strokeWidth ?? 1,
2137
- connectorStartArrow: params.startArrow,
2138
- connectorEndArrow: params.endArrow
2139
- }
2140
- };
2141
- slide.elements.push(el);
2142
- break;
2143
- }
2144
- default: {
2145
- throw new Error(`Unknown element type: ${String(params.type)}`);
2146
- }
2147
- }
2148
- return {
2149
- pptxData: ctx.pptxData,
2150
- dirty: true,
2151
- result: { elementId: id, slideIndex: params.slideIndex }
2152
- };
2153
- }
2154
- function updateElement(ctx, params) {
2155
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2156
- if (err) {
2157
- throw new Error(err);
2158
- }
2159
- const slide = ctx.pptxData.slides[params.slideIndex];
2160
- const el = slide.elements.find((e) => e.id === params.elementId);
2161
- if (!el) {
2162
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2163
- }
2164
- if (params.x !== void 0) {
2165
- el.x = params.x;
2166
- }
2167
- if (params.y !== void 0) {
2168
- el.y = params.y;
2169
- }
2170
- if (params.width !== void 0) {
2171
- el.width = params.width;
2172
- }
2173
- if (params.height !== void 0) {
2174
- el.height = params.height;
2175
- }
2176
- if (params.rotation !== void 0) {
2177
- el.rotation = params.rotation;
2178
- }
2179
- if (params.opacity !== void 0) {
2180
- el.opacity = params.opacity;
2181
- }
2182
- if (params.hidden !== void 0) {
2183
- el.hidden = params.hidden;
2184
- }
2185
- if (params.flipH !== void 0) {
2186
- el.flipHorizontal = params.flipH;
2187
- }
2188
- if (params.flipV !== void 0) {
2189
- el.flipVertical = params.flipV;
2190
- }
2191
- if (params.altText !== void 0) {
2192
- applyElementAltText(el, params.altText);
2193
- }
2194
- if (params.title !== void 0) {
2195
- applyElementTitle(el, params.title);
2196
- }
2197
- if (pptxViewerCore.hasTextProperties(el)) {
2198
- const textEl = el;
2199
- if (params.textSegments !== void 0) {
2200
- textEl.textSegments = structuredClone(params.textSegments);
2201
- textEl.text = textEl.textSegments.map((segment) => segment.text).join("");
2202
- } else if (params.text !== void 0) {
2203
- setElementText(textEl, params.text);
2204
- }
2205
- if (!textEl.textStyle) {
2206
- textEl.textStyle = {};
2207
- }
2208
- if (params.fontSize !== void 0) {
2209
- textEl.textStyle.fontSize = params.fontSize;
2210
- }
2211
- if (params.fontFamily !== void 0) {
2212
- textEl.textStyle.fontFamily = params.fontFamily;
2213
- }
2214
- if (params.fontThemeColor !== void 0) {
2215
- textEl.textStyle.colorRef = params.fontThemeColor;
2216
- const resolved = pptxViewerCore.resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
2217
- if (params.fontColor !== void 0) {
2218
- textEl.textStyle.color = params.fontColor;
2219
- } else if (resolved) {
2220
- textEl.textStyle.color = resolved;
2221
- }
2222
- } else if (params.fontColor !== void 0) {
2223
- textEl.textStyle.color = params.fontColor;
2224
- textEl.textStyle.colorRef = void 0;
2225
- }
2226
- if (params.bold !== void 0) {
2227
- textEl.textStyle.bold = params.bold;
2228
- }
2229
- if (params.italic !== void 0) {
2230
- textEl.textStyle.italic = params.italic;
2231
- }
2232
- if (params.underline !== void 0) {
2233
- textEl.textStyle.underline = params.underline;
2234
- }
2235
- if (params.alignment !== void 0) {
2236
- textEl.textStyle.align = params.alignment;
2237
- }
2238
- }
2239
- if ("shapeStyle" in el && el.shapeStyle) {
2240
- const ss = el.shapeStyle;
2241
- if (params.fillColor !== void 0) {
2242
- ss.fillColor = params.fillColor;
2243
- }
2244
- if (params.strokeColor !== void 0) {
2245
- ss.strokeColor = params.strokeColor;
2246
- }
2247
- if (params.strokeWidth !== void 0) {
2248
- ss.strokeWidth = params.strokeWidth;
2249
- }
2250
- } else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0) {
2251
- if ("shapeStyle" in el) {
2252
- el.shapeStyle = {
2253
- fillColor: params.fillColor,
2254
- strokeColor: params.strokeColor,
2255
- strokeWidth: params.strokeWidth
2256
- };
2257
- }
2258
- }
2259
- return {
2260
- pptxData: ctx.pptxData,
2261
- dirty: true,
2262
- result: { elementId: params.elementId }
2263
- };
2264
- }
2265
- function renameElement(ctx, params) {
2266
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2267
- if (err) {
2268
- throw new Error(err);
2269
- }
2270
- const slide = ctx.pptxData.slides[params.slideIndex];
2271
- const el = slide.elements.find((e) => e.id === params.elementId);
2272
- if (!el) {
2273
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2274
- }
2275
- const name = params.name.trim();
2276
- if (name.length === 0) {
2277
- delete el.name;
2278
- } else {
2279
- el.name = name;
2280
- }
2281
- return {
2282
- pptxData: ctx.pptxData,
2283
- dirty: true,
2284
- result: { elementId: params.elementId, name }
2285
- };
2286
- }
2287
- function deleteElements(ctx, params) {
2288
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2289
- if (err) {
2290
- throw new Error(err);
2291
- }
2292
- const slide = ctx.pptxData.slides[params.slideIndex];
2293
- const idSet = new Set(params.elementIds);
2294
- const existingIds = new Set(slide.elements.map((element) => element.id));
2295
- const notFound = params.elementIds.filter((id) => !existingIds.has(id));
2296
- if (notFound.length > 0) {
2297
- throw new Error(`Elements not found: ${notFound.join(", ")}`);
2298
- }
2299
- const before = slide.elements.length;
2300
- slide.elements = slide.elements.filter((e) => !idSet.has(e.id));
2301
- return {
2302
- pptxData: ctx.pptxData,
2303
- dirty: true,
2304
- result: { deletedCount: before - slide.elements.length }
2305
- };
2306
- }
2307
- function arrangeElements(ctx, params) {
2308
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2309
- if (err) {
2310
- throw new Error(err);
2311
- }
2312
- const slide = ctx.pptxData.slides[params.slideIndex];
2313
- if (params.action === "align") {
2314
- if (!params.elementIds || params.elementIds.length === 0) {
2315
- throw new Error("elementIds is required for align action.");
2316
- }
2317
- const targetIds = new Set(params.elementIds);
2318
- const targets = slide.elements.filter((element) => targetIds.has(element.id));
2319
- if (targets.length === 0) {
2320
- throw new Error("No matching elements found for align.");
2321
- }
2322
- switch (params.alignment) {
2323
- case "left": {
2324
- const minX = Math.min(...targets.map((e) => e.x));
2325
- for (const t of targets) {
2326
- t.x = minX;
2327
- }
2328
- break;
2329
- }
2330
- case "right": {
2331
- const maxRight = Math.max(...targets.map((e) => e.x + e.width));
2332
- for (const t of targets) {
2333
- t.x = maxRight - t.width;
2334
- }
2335
- break;
2336
- }
2337
- case "top": {
2338
- const minY = Math.min(...targets.map((e) => e.y));
2339
- for (const t of targets) {
2340
- t.y = minY;
2341
- }
2342
- break;
2343
- }
2344
- case "bottom": {
2345
- const maxBottom = Math.max(...targets.map((e) => e.y + e.height));
2346
- for (const t of targets) {
2347
- t.y = maxBottom - t.height;
2348
- }
2349
- break;
2350
- }
2351
- case "centerH": {
2352
- const avgCX = targets.reduce((s, e) => s + e.x + e.width / 2, 0) / targets.length;
2353
- for (const t of targets) {
2354
- t.x = avgCX - t.width / 2;
2355
- }
2356
- break;
2357
- }
2358
- case "centerV": {
2359
- const avgCY = targets.reduce((s, e) => s + e.y + e.height / 2, 0) / targets.length;
2360
- for (const t of targets) {
2361
- t.y = avgCY - t.height / 2;
2362
- }
2363
- break;
2364
- }
2365
- default: {
2366
- throw new Error(`Unknown alignment: ${String(params.alignment)}`);
2367
- }
2368
- }
2369
- } else if (params.action === "reorderLayer") {
2370
- if (!params.elementId) {
2371
- throw new Error("elementId is required for reorderLayer action.");
2372
- }
2373
- const idx = slide.elements.findIndex((e) => e.id === params.elementId);
2374
- if (idx < 0) {
2375
- throw new Error(`Element '${params.elementId}' not found.`);
2376
- }
2377
- const [el] = slide.elements.splice(idx, 1);
2378
- switch (params.layerAction) {
2379
- case "bringToFront":
2380
- slide.elements.push(el);
2381
- break;
2382
- case "sendToBack":
2383
- slide.elements.unshift(el);
2384
- break;
2385
- case "bringForward": {
2386
- const newIdx = Math.min(idx + 1, slide.elements.length);
2387
- slide.elements.splice(newIdx, 0, el);
2388
- break;
2389
- }
2390
- case "sendBackward": {
2391
- const newIdx = Math.max(idx - 1, 0);
2392
- slide.elements.splice(newIdx, 0, el);
2393
- break;
2394
- }
2395
- default: {
2396
- slide.elements.splice(idx, 0, el);
2397
- throw new Error(`Unknown layerAction: ${String(params.layerAction)}`);
2398
- }
2399
- }
2400
- } else {
2401
- throw new Error(`Unknown action: ${String(params.action)}`);
2402
- }
2403
- return {
2404
- pptxData: ctx.pptxData,
2405
- dirty: true,
2406
- result: { slideIndex: params.slideIndex }
2407
- };
2408
- }
2409
- function cloneElement(ctx, params) {
2410
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2411
- if (err) {
2412
- throw new Error(err);
2413
- }
2414
- const srcSlide = ctx.pptxData.slides[params.slideIndex];
2415
- const original = srcSlide.elements.find((e) => e.id === params.elementId);
2416
- if (!original) {
2417
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2418
- }
2419
- const targets = params.targetSlideIndexes ?? [params.slideIndex];
2420
- const clonedIds = [];
2421
- const offsetX = params.offsetX ?? 20;
2422
- const offsetY = params.offsetY ?? 20;
2423
- for (const targetIdx of targets) {
2424
- const terr = validateSlideIndex(targetIdx, ctx.pptxData.slides.length);
2425
- if (terr) {
2426
- throw new Error(terr);
2427
- }
2428
- const clone = pptxViewerCore.cloneElement(original);
2429
- const intoTemplate = pptxViewerCore.isTemplateElementId(original.id);
2430
- clone.id = pptxViewerCore.makeStoreAwareId(intoTemplate, original.id);
2431
- pptxViewerCore.reassignDescendantIds(clone, () => pptxViewerCore.makeStoreAwareId(intoTemplate, original.id));
2432
- clone.x += offsetX;
2433
- clone.y += offsetY;
2434
- ctx.pptxData.slides[targetIdx].elements.push(clone);
2435
- clonedIds.push(clone.id);
2436
- }
2437
- return {
2438
- pptxData: ctx.pptxData,
2439
- dirty: true,
2440
- result: { clonedIds }
2441
- };
2442
- }
2443
- function setElementAnimation(ctx, params) {
2444
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2445
- if (err) {
2446
- throw new Error(err);
2447
- }
2448
- const slide = ctx.pptxData.slides[params.slideIndex];
2449
- const elExists = slide.elements.some((e) => e.id === params.elementId);
2450
- if (!elExists) {
2451
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2452
- }
2453
- if (!slide.animations) {
2454
- slide.animations = [];
2455
- }
2456
- const existing = slide.animations.find((a) => a.elementId === params.elementId);
2457
- if (existing) {
2458
- if (params.entrance !== void 0) {
2459
- existing.entrance = params.entrance;
2460
- }
2461
- if (params.exit !== void 0) {
2462
- existing.exit = params.exit;
2463
- }
2464
- if (params.durationMs !== void 0) {
2465
- existing.durationMs = params.durationMs;
2466
- }
2467
- if (params.delayMs !== void 0) {
2468
- existing.delayMs = params.delayMs;
2469
- }
2470
- if (params.order !== void 0) {
2471
- existing.order = params.order;
2472
- }
2473
- } else {
2474
- const anim = {
2475
- elementId: params.elementId,
2476
- entrance: params.entrance,
2477
- exit: params.exit,
2478
- durationMs: params.durationMs,
2479
- delayMs: params.delayMs,
2480
- order: params.order
2481
- };
2482
- slide.animations.push(anim);
2483
- }
2484
- return {
2485
- pptxData: ctx.pptxData,
2486
- dirty: true,
2487
- result: { elementId: params.elementId }
2488
- };
2489
- }
2490
- function groupElements(ctx, params) {
2491
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2492
- if (err) {
2493
- throw new Error(err);
2494
- }
2495
- if (params.elementIds.length < 2) {
2496
- throw new Error("At least 2 elements are required to form a group.");
2497
- }
2498
- const slide = ctx.pptxData.slides[params.slideIndex];
2499
- const idSet = new Set(params.elementIds);
2500
- const found = new Set(slide.elements.filter((e) => idSet.has(e.id)).map((e) => e.id));
2501
- if (found.size !== idSet.size) {
2502
- const missing = params.elementIds.filter((id) => !found.has(id));
2503
- throw new Error(`Elements not found: ${missing.join(", ")}`);
2504
- }
2505
- const groupId = generateElementId();
2506
- const grouped = pptxViewerCore.groupElements(slide.elements, params.elementIds, groupId);
2507
- slide.elements = grouped.elements;
2508
- return {
2509
- pptxData: ctx.pptxData,
2510
- dirty: true,
2511
- result: { groupId: grouped.groupId ?? groupId }
2512
- };
2513
- }
2514
- function ungroupElements(ctx, params) {
2515
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2516
- if (err) {
2517
- throw new Error(err);
2518
- }
2519
- const slide = ctx.pptxData.slides[params.slideIndex];
2520
- const group = slide.elements.find((e) => e.id === params.groupElementId);
2521
- if (!group) {
2522
- throw new Error(`Group element '${params.groupElementId}' not found.`);
2523
- }
2524
- if (group.type !== "group") {
2525
- throw new Error(`Element '${params.groupElementId}' is not a group.`);
2526
- }
2527
- const intoTemplate = pptxViewerCore.isTemplateElementId(group.id);
2528
- const childIds = group.children.map(
2529
- (child) => pptxViewerCore.isTemplateElementId(child.id) === intoTemplate ? child.id : pptxViewerCore.makeStoreAwareId(intoTemplate, group.id)
2530
- );
2531
- const promoted = pptxViewerCore.ungroupElements(slide.elements, params.groupElementId, childIds, {
2532
- intoTemplate
2533
- });
2534
- slide.elements = promoted.elements;
2535
- return {
2536
- pptxData: ctx.pptxData,
2537
- dirty: true,
2538
- result: { restoredIds: promoted.childIds }
2539
- };
2540
- }
2541
- function batchUpdateElements(ctx, params) {
2542
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2543
- if (err) {
2544
- throw new Error(err);
2545
- }
2546
- const slide = ctx.pptxData.slides[params.slideIndex];
2547
- const idSet = new Set(params.elementIds);
2548
- let count = 0;
2549
- for (const el of slide.elements) {
2550
- if (!idSet.has(el.id)) {
2551
- continue;
2552
- }
2553
- if (params.x !== void 0) {
2554
- el.x = params.x;
2555
- }
2556
- if (params.y !== void 0) {
2557
- el.y = params.y;
2558
- }
2559
- if (params.width !== void 0) {
2560
- el.width = params.width;
2561
- }
2562
- if (params.height !== void 0) {
2563
- el.height = params.height;
2564
- }
2565
- if (params.rotation !== void 0) {
2566
- el.rotation = params.rotation;
2567
- }
2568
- if (params.opacity !== void 0) {
2569
- el.opacity = params.opacity;
2570
- }
2571
- if (params.hidden !== void 0) {
2572
- el.hidden = params.hidden;
2573
- }
2574
- count++;
2575
- }
2576
- return {
2577
- pptxData: ctx.pptxData,
2578
- dirty: true,
2579
- result: { updatedCount: count }
2580
- };
2581
- }
2582
- function exportToSvg(ctx, params) {
2583
- if (params.slideIndices) {
2584
- for (const si of params.slideIndices) {
2585
- const err = validateSlideIndex(si, ctx.pptxData.slides.length);
2586
- if (err) {
2587
- throw new Error(err);
2588
- }
2589
- }
2590
- }
2591
- const options = {};
2592
- if (params.slideIndices) {
2593
- options.slideIndices = params.slideIndices;
2594
- }
2595
- if (params.includeHidden !== void 0) {
2596
- options.includeHidden = params.includeHidden;
2597
- }
2598
- if (params.defaultFontFamily) {
2599
- options.defaultFontFamily = params.defaultFontFamily;
2600
- }
2601
- if (params.defaultFontSize) {
2602
- options.defaultFontSize = params.defaultFontSize;
2603
- }
2604
- const svgStrings = pptxViewerCore.SvgExporter.exportAll(ctx.pptxData, options);
2605
- return {
2606
- pptxData: ctx.pptxData,
2607
- dirty: false,
2608
- result: { svgStrings, slideCount: svgStrings.length }
2609
- };
2610
- }
2611
- function exportSlideSvg(ctx, params) {
2612
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2613
- if (err) {
2614
- throw new Error(err);
2615
- }
2616
- const slide = ctx.pptxData.slides[params.slideIndex];
2617
- const width = ctx.pptxData.width ?? 960;
2618
- const height = ctx.pptxData.height ?? 540;
2619
- const options = {};
2620
- if (params.defaultFontFamily) {
2621
- options.defaultFontFamily = params.defaultFontFamily;
2622
- }
2623
- if (params.defaultFontSize) {
2624
- options.defaultFontSize = params.defaultFontSize;
2625
- }
2626
- const svg = pptxViewerCore.SvgExporter.exportSlide(slide, width, height, options);
2627
- return {
2628
- pptxData: ctx.pptxData,
2629
- dirty: false,
2630
- result: { svg, slideIndex: params.slideIndex }
2631
- };
2632
- }
2633
- function replaceGeometry(ctx, params) {
2634
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2635
- if (err) {
2636
- throw new Error(err);
2637
- }
2638
- const slide = ctx.pptxData.slides[params.slideIndex];
2639
- const el = slide.elements.find((e) => e.id === params.elementId);
2640
- if (!el) {
2641
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2642
- }
2643
- if (el.type !== "shape") {
2644
- throw new Error(`Element '${params.elementId}' is not a shape.`);
2645
- }
2646
- const shape = el;
2647
- if (params.svgPath) {
2648
- pptxViewerCore.replaceWithCustomGeometry(shape, params.svgPath, params.pathWidth, params.pathHeight);
2649
- return {
2650
- pptxData: ctx.pptxData,
2651
- dirty: true,
2652
- result: { elementId: params.elementId, geometryType: "custom" }
2653
- };
2654
- }
2655
- if (params.shapeType) {
2656
- pptxViewerCore.replaceShapeGeometry(shape, params.shapeType, params.adjustments);
2657
- return {
2658
- pptxData: ctx.pptxData,
2659
- dirty: true,
2660
- result: { elementId: params.elementId, geometryType: params.shapeType }
2661
- };
2662
- }
2663
- throw new Error("Either shapeType or svgPath must be provided.");
2664
- }
2665
-
2666
- // src/tools/hyperlink-tools.ts
2667
- function manageHyperlinks(ctx, params) {
2668
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2669
- if (err) {
2670
- throw new Error(err);
2671
- }
2672
- const slide = ctx.pptxData.slides[params.slideIndex];
2673
- switch (params.action) {
2674
- case "list": {
2675
- const hyperlinks = [];
2676
- for (const el of slide.elements) {
2677
- if (el.actionClick) {
2678
- hyperlinks.push({
2679
- elementId: el.id,
2680
- trigger: "click",
2681
- url: el.actionClick.url,
2682
- tooltip: el.actionClick.tooltip,
2683
- targetSlideIndex: el.actionClick.targetSlideIndex,
2684
- actionType: el.actionClick.action
2685
- });
2686
- }
2687
- if (el.actionHover) {
2688
- hyperlinks.push({
2689
- elementId: el.id,
2690
- trigger: "hover",
2691
- url: el.actionHover.url,
2692
- tooltip: el.actionHover.tooltip,
2693
- targetSlideIndex: el.actionHover.targetSlideIndex,
2694
- actionType: el.actionHover.action
2695
- });
2696
- }
2697
- }
2698
- return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", hyperlinks } };
2699
- }
2700
- case "set": {
2701
- if (!params.elementId) {
2702
- throw new Error("elementId is required for set action.");
2703
- }
2704
- const el = slide.elements.find((e) => e.id === params.elementId);
2705
- if (!el) {
2706
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2707
- }
2708
- const trigger = params.trigger ?? "click";
2709
- const action = {};
2710
- if (params.url) {
2711
- action.url = params.url;
2712
- }
2713
- if (params.tooltip) {
2714
- action.tooltip = params.tooltip;
2715
- }
2716
- if (params.targetSlideIndex !== void 0) {
2717
- action.targetSlideIndex = params.targetSlideIndex;
2718
- }
2719
- if (params.actionType) {
2720
- switch (params.actionType) {
2721
- case "url":
2722
- action.action = "ppaction://hlinkpres";
2723
- break;
2724
- case "slide":
2725
- action.action = "ppaction://hlinksldjump";
2726
- break;
2727
- case "nextSlide":
2728
- action.action = "ppaction://hlinkshowjump?jump=nextslide";
2729
- break;
2730
- case "prevSlide":
2731
- action.action = "ppaction://hlinkshowjump?jump=previousslide";
2732
- break;
2733
- case "firstSlide":
2734
- action.action = "ppaction://hlinkshowjump?jump=firstslide";
2735
- break;
2736
- case "lastSlide":
2737
- action.action = "ppaction://hlinkshowjump?jump=lastslide";
2738
- break;
2739
- case "endShow":
2740
- action.action = "ppaction://hlinkshowjump?jump=endshow";
2741
- break;
2742
- }
2743
- }
2744
- if (trigger === "click") {
2745
- el.actionClick = action;
2746
- } else {
2747
- el.actionHover = action;
2748
- }
2749
- return {
2750
- pptxData: ctx.pptxData,
2751
- dirty: true,
2752
- result: { action: "set", elementId: params.elementId }
2753
- };
2754
- }
2755
- case "remove": {
2756
- if (!params.elementId) {
2757
- throw new Error("elementId is required for remove action.");
2758
- }
2759
- const el = slide.elements.find((e) => e.id === params.elementId);
2760
- if (!el) {
2761
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2762
- }
2763
- const trigger = params.trigger ?? "click";
2764
- if (trigger === "click") {
2765
- el.actionClick = void 0;
2766
- } else {
2767
- el.actionHover = void 0;
2768
- }
2769
- return {
2770
- pptxData: ctx.pptxData,
2771
- dirty: true,
2772
- result: { action: "remove", elementId: params.elementId }
2773
- };
2774
- }
2775
- default:
2776
- throw new Error(`Unknown hyperlink action: ${String(params.action)}`);
2777
- }
2778
- }
2779
- function exportToJson(ctx, params) {
2780
- const document = pptxViewerCore.buildPptxJsonDocument(ctx.pptxData, { generator: "pptx-viewer-mcp" });
2781
- const json = JSON.stringify(document, null, params.pretty === false ? void 0 : 2);
2782
- return {
2783
- pptxData: ctx.pptxData,
2784
- dirty: false,
2785
- result: {
2786
- json,
2787
- slideCount: document.slideCount,
2788
- byteSize: new TextEncoder().encode(json).byteLength,
2789
- assets: document.assets
2790
- }
2791
- };
2792
- }
2793
- function importFromJson(ctx, params) {
2794
- const imported = pptxViewerCore.deserializePptxFromJson(params.json);
2795
- pptxViewerCore.applyImportedPptxData(ctx.pptxData, imported);
2796
- return {
2797
- pptxData: ctx.pptxData,
2798
- dirty: true,
2799
- result: {
2800
- slideCount: ctx.pptxData.slides.length,
2801
- width: ctx.pptxData.width,
2802
- height: ctx.pptxData.height
2803
- }
2804
- };
2805
- }
2806
- function getLayouts(ctx) {
2807
- const layouts = [];
2808
- if (ctx.pptxData.slideMasters) {
2809
- for (const master of ctx.pptxData.slideMasters) {
2810
- if (master.layouts) {
2811
- for (const layout of master.layouts) {
2812
- layouts.push({
2813
- name: layout.name ?? "Unknown",
2814
- path: layout.path
2815
- });
2816
- }
2817
- }
2818
- }
2819
- }
2820
- if (ctx.pptxData.layoutOptions) {
2821
- for (const opt of ctx.pptxData.layoutOptions) {
2822
- if (!layouts.some((l) => l.path === opt.path)) {
2823
- layouts.push({ name: opt.name, path: opt.path, type: opt.type });
2824
- }
2825
- }
2826
- }
2827
- return {
2828
- pptxData: ctx.pptxData,
2829
- dirty: false,
2830
- result: { layouts, count: layouts.length }
2831
- };
2832
- }
2833
- function applyLayout(ctx, params) {
2834
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2835
- if (err) {
2836
- throw new Error(err);
2837
- }
2838
- let layout;
2839
- if (params.layoutName) {
2840
- layout = pptxViewerCore.findLayoutByName(ctx.pptxData, params.layoutName);
2841
- } else if (params.layoutType) {
2842
- layout = pptxViewerCore.findLayoutByType(ctx.pptxData, params.layoutType);
2843
- } else {
2844
- throw new Error("Either layoutName or layoutType must be provided.");
2845
- }
2846
- if (!layout) {
2847
- throw new Error(
2848
- `Layout not found: ${params.layoutName ?? params.layoutType}. Use get_layouts to see available layouts.`
2849
- );
2850
- }
2851
- const slide = ctx.pptxData.slides[params.slideIndex];
2852
- slide.layoutName = layout.name;
2853
- if (layout.path) {
2854
- slide.layoutPath = layout.path;
2855
- }
2856
- const master = ctx.pptxData.slideMasters?.find(
2857
- (candidate) => candidate.layouts?.some((definition2) => definition2.path === layout.path)
2858
- );
2859
- const definition = master?.layouts?.find((candidate) => candidate.path === layout.path);
2860
- for (const frame of definition?.placeholders ?? []) {
2861
- if (["dt", "ftr", "sldnum", "hdr"].includes(frame.type)) {
2862
- continue;
2863
- }
2864
- const ph = {
2865
- "@_type": frame.type === "ctrtitle" ? "ctrTitle" : frame.type,
2866
- ...frame.idx !== void 0 ? { "@_idx": frame.idx } : {}
2867
- };
2868
- if (slide.elements.some((element) => {
2869
- const nv = element.rawXml?.["p:nvSpPr"];
2870
- const nvPr = nv?.["p:nvPr"];
2871
- const existing = nvPr?.["p:ph"];
2872
- return element.placeholderType === frame.type && String(existing?.["@_idx"] ?? "0") === String(frame.idx ?? "0");
2873
- })) {
2874
- continue;
2875
- }
2876
- const inherited = master?.placeholders?.find(
2877
- (candidate) => candidate.type === frame.type && (candidate.idx ?? "0") === (frame.idx ?? "0")
2878
- ) ?? master?.placeholders?.find((candidate) => candidate.type === frame.type);
2879
- slide.elements.push({
2880
- id: generateElementId(),
2881
- type: "text",
2882
- placeholderType: frame.type,
2883
- x: frame.x ?? inherited?.x ?? 0,
2884
- y: frame.y ?? inherited?.y ?? 0,
2885
- width: frame.width ?? inherited?.width ?? ctx.pptxData.width,
2886
- height: frame.height ?? inherited?.height ?? ctx.pptxData.height,
2887
- text: "",
2888
- textSegments: [{ text: "", style: {} }],
2889
- rawXml: {
2890
- "p:nvSpPr": {
2891
- "p:cNvPr": { "@_name": frame.type },
2892
- "p:cNvSpPr": {},
2893
- "p:nvPr": { "p:ph": ph }
2894
- },
2895
- "p:spPr": {}
2896
- }
2897
- });
2898
- }
2899
- return {
2900
- pptxData: ctx.pptxData,
2901
- dirty: true,
2902
- result: { slideIndex: params.slideIndex, layoutName: layout.name ?? "Unknown" }
2903
- };
2904
- }
2905
- function setElementLockT(ctx, params) {
2906
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
2907
- if (err) {
2908
- throw new Error(err);
2909
- }
2910
- const slide = ctx.pptxData.slides[params.slideIndex];
2911
- const idx = slide.elements.findIndex((e) => e.id === params.elementId);
2912
- if (idx < 0) {
2913
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
2914
- }
2915
- const extraLocks = {};
2916
- if (params.noMove !== void 0) {
2917
- extraLocks["noMove"] = params.noMove;
2918
- }
2919
- if (params.noResize !== void 0) {
2920
- extraLocks["noResize"] = params.noResize;
2921
- }
2922
- if (params.noRotation !== void 0) {
2923
- extraLocks["noRotation"] = params.noRotation;
2924
- }
2925
- if (params.noSelect !== void 0) {
2926
- extraLocks["noSelect"] = params.noSelect;
2927
- }
2928
- if (params.noTextEdit !== void 0) {
2929
- extraLocks["noTextEdit"] = params.noTextEdit;
2930
- }
2931
- const updated = pptxViewerCore.setElementLocked(slide.elements[idx], params.locked, extraLocks);
2932
- slide.elements[idx] = updated;
2933
- return {
2934
- pptxData: ctx.pptxData,
2935
- dirty: true,
2936
- result: { elementId: params.elementId, locked: params.locked }
2937
- };
2938
- }
2939
-
2940
- // src/tools/metadata-tools.ts
2941
- function getMetadata(ctx) {
2942
- return {
2943
- pptxData: ctx.pptxData,
2944
- dirty: false,
2945
- result: {
2946
- coreProperties: ctx.pptxData.coreProperties,
2947
- appProperties: ctx.pptxData.appProperties,
2948
- customProperties: ctx.pptxData.customProperties,
2949
- slideCount: ctx.pptxData.slides.length
2950
- }
2951
- };
2952
- }
2953
- function updateMetadata(ctx, params) {
2954
- const updated = [];
2955
- if (params.title !== void 0 || params.subject !== void 0 || params.creator !== void 0 || params.keywords !== void 0 || params.description !== void 0 || params.lastModifiedBy !== void 0 || params.category !== void 0) {
2956
- if (!ctx.pptxData.coreProperties) {
2957
- ctx.pptxData.coreProperties = {};
2958
- }
2959
- const cp = ctx.pptxData.coreProperties;
2960
- if (params.title !== void 0) {
2961
- cp.title = params.title;
2962
- updated.push("title");
2963
- }
2964
- if (params.subject !== void 0) {
2965
- cp.subject = params.subject;
2966
- updated.push("subject");
2967
- }
2968
- if (params.creator !== void 0) {
2969
- cp.creator = params.creator;
2970
- updated.push("creator");
2971
- }
2972
- if (params.keywords !== void 0) {
2973
- cp.keywords = params.keywords;
2974
- updated.push("keywords");
2975
- }
2976
- if (params.description !== void 0) {
2977
- cp.description = params.description;
2978
- updated.push("description");
2979
- }
2980
- if (params.lastModifiedBy !== void 0) {
2981
- cp.lastModifiedBy = params.lastModifiedBy;
2982
- updated.push("lastModifiedBy");
2983
- }
2984
- if (params.category !== void 0) {
2985
- cp.category = params.category;
2986
- updated.push("category");
2987
- }
2988
- }
2989
- if (params.company !== void 0 || params.manager !== void 0) {
2990
- if (!ctx.pptxData.appProperties) {
2991
- ctx.pptxData.appProperties = {};
2992
- }
2993
- const ap = ctx.pptxData.appProperties;
2994
- if (params.company !== void 0) {
2995
- ap.company = params.company;
2996
- updated.push("company");
2997
- }
2998
- if (params.manager !== void 0) {
2999
- ap.manager = params.manager;
3000
- updated.push("manager");
3001
- }
3002
- }
3003
- if (params.customProperties) {
3004
- if (!ctx.pptxData.customProperties) {
3005
- ctx.pptxData.customProperties = [];
3006
- }
3007
- for (const cp of params.customProperties) {
3008
- const valueStr = String(cp.value);
3009
- const vtType = typeof cp.value === "number" ? "i4" : typeof cp.value === "boolean" ? "bool" : "lpwstr";
3010
- const existing = ctx.pptxData.customProperties.find((p) => p.name === cp.name);
3011
- if (existing) {
3012
- existing.value = valueStr;
3013
- existing.type = vtType;
3014
- } else {
3015
- ctx.pptxData.customProperties.push({ name: cp.name, value: valueStr, type: vtType });
3016
- }
3017
- updated.push(`custom:${cp.name}`);
3018
- }
3019
- }
3020
- return {
3021
- pptxData: ctx.pptxData,
3022
- dirty: updated.length > 0,
3023
- result: { updated }
3024
- };
3025
- }
3026
- function resolveOleElement(ctx, slideIndex, elementId) {
3027
- const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
3028
- if (err) {
3029
- throw new Error(err);
3030
- }
3031
- const slide = ctx.pptxData.slides[slideIndex];
3032
- const index = slide.elements.findIndex((e) => e.id === elementId);
3033
- if (index === -1) {
3034
- throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
3035
- }
3036
- const element = slide.elements[index];
3037
- if (element.type !== "ole") {
3038
- throw new Error(`Element '${elementId}' is not an OLE object.`);
3039
- }
3040
- return { slide, element, index };
3041
- }
3042
- function commitOleElement(slide, index, updated) {
3043
- slide.elements.splice(index, 1, updated);
3044
- slide.isDirty = true;
3045
- }
3046
- async function getOleContent(ctx, params) {
3047
- const { element } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3048
- const kind = await pptxViewerCore.resolveOleEditorKindFromPayload(element);
3049
- const base = { pptxData: ctx.pptxData, dirty: false };
3050
- switch (kind) {
3051
- case "sheet-xlsx":
3052
- case "sheet-xls": {
3053
- const sheet = await pptxViewerCore.getOleSheetGrid(element);
3054
- return { ...base, result: { elementId: element.id, kind, editable: true, sheet } };
3055
- }
3056
- case "document-docx":
3057
- case "document-doc": {
3058
- const paragraphs = await pptxViewerCore.getOleDocumentParagraphs(element);
3059
- return { ...base, result: { elementId: element.id, kind, editable: true, paragraphs } };
3060
- }
3061
- case "deck-pptx": {
3062
- const deckSlides = await pptxViewerCore.getOleNestedDeckDetail(element);
3063
- return { ...base, result: { elementId: element.id, kind, editable: true, deckSlides } };
3064
- }
3065
- default:
3066
- return {
3067
- ...base,
3068
- result: {
3069
- elementId: element.id,
3070
- kind,
3071
- editable: false,
3072
- message: `This OLE object's content (${kind}) is not directly editable; use ole_replace_file to replace it wholesale.`
3073
- }
3074
- };
3075
- }
3076
- }
3077
- async function setOleSheetCell(ctx, params) {
3078
- const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3079
- const updated = await pptxViewerCore.applyOleSheetCellEdit(element, {
3080
- row: params.row,
3081
- col: params.col,
3082
- value: params.value
3083
- });
3084
- const changed = updated !== element;
3085
- if (changed) {
3086
- commitOleElement(slide, index, updated);
3087
- }
3088
- return {
3089
- pptxData: ctx.pptxData,
3090
- dirty: changed,
3091
- result: { elementId: params.elementId, changed }
3092
- };
3093
- }
3094
- async function setOleDocumentParagraph(ctx, params) {
3095
- const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3096
- const updated = await pptxViewerCore.applyOleDocumentParagraphEdit(element, params.paragraphIndex, params.text);
3097
- const changed = updated !== element;
3098
- if (changed) {
3099
- commitOleElement(slide, index, updated);
3100
- }
3101
- return {
3102
- pptxData: ctx.pptxData,
3103
- dirty: changed,
3104
- result: { elementId: params.elementId, changed }
3105
- };
3106
- }
3107
- async function setOleDeckSlideTitle(ctx, params) {
3108
- const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3109
- const updated = await pptxViewerCore.applyOleNestedDeckElementTextEdit(
3110
- element,
3111
- params.deckSlideIndex,
3112
- params.deckElementId,
3113
- params.title
3114
- );
3115
- const changed = updated !== element;
3116
- if (changed) {
3117
- commitOleElement(slide, index, updated);
3118
- }
3119
- return {
3120
- pptxData: ctx.pptxData,
3121
- dirty: changed,
3122
- result: { elementId: params.elementId, changed }
3123
- };
3124
- }
3125
- async function setOleObjectNameT(ctx, params) {
3126
- const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3127
- const updated = await pptxViewerCore.setOleObjectName(element, params.name);
3128
- commitOleElement(slide, index, updated);
3129
- return {
3130
- pptxData: ctx.pptxData,
3131
- dirty: true,
3132
- result: { elementId: params.elementId, changed: true }
3133
- };
3134
- }
3135
- async function replaceOleFileT(ctx, params) {
3136
- const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
3137
- const parsed = pptxViewerCore.parseDataUrlToBytes(params.fileData);
3138
- if (!parsed) {
3139
- throw new Error('fileData must be a base64 data URL, e.g. "data:<mime-type>;base64,<...>".');
3140
- }
3141
- const updated = await pptxViewerCore.replaceOleFile(element, parsed.bytes, params.fileName);
3142
- commitOleElement(slide, index, updated);
3143
- return {
3144
- pptxData: ctx.pptxData,
3145
- dirty: true,
3146
- result: { elementId: params.elementId, changed: true }
3147
- };
3148
- }
3149
-
3150
- // src/tools/presentation-tools.ts
3151
- function getPresentationProperties(ctx) {
3152
- return {
3153
- pptxData: ctx.pptxData,
3154
- dirty: false,
3155
- result: {
3156
- properties: ctx.pptxData.presentationProperties,
3157
- slideCount: ctx.pptxData.slides.length,
3158
- width: ctx.pptxData.width,
3159
- height: ctx.pptxData.height
3160
- }
3161
- };
3162
- }
3163
- function updatePresentationProperties(ctx, params) {
3164
- if (!ctx.pptxData.presentationProperties) {
3165
- ctx.pptxData.presentationProperties = {};
3166
- }
3167
- const pp = ctx.pptxData.presentationProperties;
3168
- if (params.showType !== void 0) {
3169
- pp.showType = params.showType;
3170
- }
3171
- if (params.loopContinuously !== void 0) {
3172
- pp.loopContinuously = params.loopContinuously;
3173
- }
3174
- if (params.showWithNarration !== void 0) {
3175
- pp.showWithNarration = params.showWithNarration;
3176
- }
3177
- if (params.showWithAnimation !== void 0) {
3178
- pp.showWithAnimation = params.showWithAnimation;
3179
- }
3180
- if (params.advanceMode !== void 0) {
3181
- pp.advanceMode = params.advanceMode;
3182
- }
3183
- if (params.showSlidesMode !== void 0) {
3184
- pp.showSlidesMode = params.showSlidesMode;
3185
- }
3186
- if (params.showSlidesFrom !== void 0) {
3187
- pp.showSlidesFrom = params.showSlidesFrom;
3188
- }
3189
- if (params.showSlidesTo !== void 0) {
3190
- pp.showSlidesTo = params.showSlidesTo;
3191
- }
3192
- if (params.penColor !== void 0) {
3193
- pp.penColor = params.penColor;
3194
- }
3195
- return {
3196
- pptxData: ctx.pptxData,
3197
- dirty: true,
3198
- result: { properties: pp }
3199
- };
3200
- }
3201
- function manageSections(ctx, params) {
3202
- switch (params.action) {
3203
- case "list": {
3204
- const sections = (ctx.pptxData.sections ?? []).map((s) => ({
3205
- id: s.id,
3206
- name: s.name,
3207
- slideIds: s.slideIds,
3208
- collapsed: s.collapsed,
3209
- color: s.color
3210
- }));
3211
- return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", sections } };
3212
- }
3213
- case "add": {
3214
- if (!params.name) {
3215
- throw new Error("name is required for add action.");
3216
- }
3217
- const section = pptxViewerCore.addSection(ctx.pptxData, params.name, params.slideIndices ?? []);
3218
- return {
3219
- pptxData: ctx.pptxData,
3220
- dirty: true,
3221
- result: {
3222
- action: "add",
3223
- section: { id: section.id, name: section.name, slideIds: section.slideIds }
3224
- }
3225
- };
3226
- }
3227
- case "remove": {
3228
- if (!params.sectionId) {
3229
- throw new Error("sectionId is required for remove action.");
3230
- }
3231
- const success = pptxViewerCore.removeSection(ctx.pptxData, params.sectionId);
3232
- return { pptxData: ctx.pptxData, dirty: success, result: { action: "remove", success } };
3233
- }
3234
- case "reorder": {
3235
- if (!params.sectionIds) {
3236
- throw new Error("sectionIds is required for reorder action.");
3237
- }
3238
- pptxViewerCore.reorderSections(ctx.pptxData, params.sectionIds);
3239
- return { pptxData: ctx.pptxData, dirty: true, result: { action: "reorder", success: true } };
3240
- }
3241
- case "moveSlides": {
3242
- if (!params.sectionId) {
3243
- throw new Error("sectionId is required for moveSlides action.");
3244
- }
3245
- if (!params.slideIndices) {
3246
- throw new Error("slideIndices is required for moveSlides action.");
3247
- }
3248
- const success = pptxViewerCore.moveSlidesToSection(ctx.pptxData, params.slideIndices, params.sectionId);
3249
- return { pptxData: ctx.pptxData, dirty: success, result: { action: "moveSlides", success } };
3250
- }
3251
- case "getForSlide": {
3252
- if (params.slideIndex === void 0) {
3253
- throw new Error("slideIndex is required for getForSlide action.");
3254
- }
3255
- const section = pptxViewerCore.getSectionForSlide(ctx.pptxData, params.slideIndex);
3256
- const info = section ? { id: section.id, name: section.name, slideIds: section.slideIds } : null;
3257
- return {
3258
- pptxData: ctx.pptxData,
3259
- dirty: false,
3260
- result: { action: "getForSlide", section: info }
3261
- };
3262
- }
3263
- default:
3264
- throw new Error(`Unknown section action: ${String(params.action)}`);
3265
- }
3266
- }
3267
-
3268
- // src/tools/slide-tools.ts
3269
- function getSlide(ctx, params) {
3270
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3271
- if (err) {
3272
- throw new Error(err);
3273
- }
3274
- const slide = ctx.pptxData.slides[params.slideIndex];
3275
- return {
3276
- pptxData: ctx.pptxData,
3277
- dirty: false,
3278
- result: {
3279
- slideIndex: params.slideIndex,
3280
- slideNumber: slide.slideNumber,
3281
- hidden: slide.hidden ?? false,
3282
- layoutName: slide.layoutName,
3283
- backgroundColor: slide.backgroundColor,
3284
- notes: slide.notes ?? "",
3285
- commentCount: slide.comments?.length ?? 0,
3286
- elements: slide.elements.map(describeElement)
3287
- }
3288
- };
3289
- }
3290
- function addSlide(ctx, params) {
3291
- const { slides } = ctx.pptxData;
3292
- const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
3293
- const newSlide = {
3294
- id: generateSlideId(),
3295
- rId: "",
3296
- slideNumber: insertAt + 1,
3297
- elements: [],
3298
- backgroundColor: params.backgroundColor
3299
- };
3300
- slides.splice(insertAt, 0, newSlide);
3301
- slides.forEach((s, i) => {
3302
- s.slideNumber = i + 1;
3303
- });
3304
- return {
3305
- pptxData: ctx.pptxData,
3306
- dirty: true,
3307
- result: { newSlideIndex: insertAt, slideCount: slides.length }
3308
- };
3309
- }
3310
- function deleteSlides(ctx, params) {
3311
- const { slides } = ctx.pptxData;
3312
- if (!params.slideIndexes || params.slideIndexes.length === 0) {
3313
- throw new Error("slideIndexes is required for the delete action.");
3314
- }
3315
- const indexSet = new Set(params.slideIndexes);
3316
- const invalid = params.slideIndexes.filter((i) => i < 0 || i >= slides.length);
3317
- if (invalid.length > 0) {
3318
- throw new Error(
3319
- `Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
3320
- );
3321
- }
3322
- if (indexSet.size >= slides.length) {
3323
- throw new Error("Cannot delete all slides. At least one slide must remain.");
3324
- }
3325
- ctx.pptxData.slides = slides.filter((_, i) => !indexSet.has(i));
3326
- ctx.pptxData.slides.forEach((s, i) => {
3327
- s.slideNumber = i + 1;
3328
- });
3329
- return {
3330
- pptxData: ctx.pptxData,
3331
- dirty: true,
3332
- result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
3333
- };
3334
- }
3335
- function reorderSlides(ctx, params) {
3336
- const { slides } = ctx.pptxData;
3337
- if (!params.newOrder || params.newOrder.length !== slides.length) {
3338
- throw new Error(
3339
- `newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
3340
- );
3341
- }
3342
- const sorted = [...params.newOrder].sort((a, b) => a - b);
3343
- const expected = slides.map((_, i) => i);
3344
- if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
3345
- throw new Error(
3346
- `newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
3347
- );
3348
- }
3349
- ctx.pptxData.slides = params.newOrder.map((idx) => slides[idx]);
3350
- ctx.pptxData.slides.forEach((s, i) => {
3351
- s.slideNumber = i + 1;
3352
- });
3353
- return {
3354
- pptxData: ctx.pptxData,
3355
- dirty: true,
3356
- result: { slideCount: ctx.pptxData.slides.length }
3357
- };
3358
- }
3359
- function duplicateSlide(ctx, params) {
3360
- const { slides } = ctx.pptxData;
3361
- const err = validateSlideIndex(params.slideIndex, slides.length);
3362
- if (err) {
3363
- throw new Error(err);
3364
- }
3365
- const original = slides[params.slideIndex];
3366
- const clone = structuredClone(original);
3367
- clone.id = generateSlideId();
3368
- clone.rId = "";
3369
- for (const el of clone.elements) {
3370
- el.id = generateElementId();
3371
- }
3372
- const insertIndex = params.targetIndex ?? params.slideIndex + 1;
3373
- slides.splice(insertIndex, 0, clone);
3374
- slides.forEach((s, i) => {
3375
- s.slideNumber = i + 1;
3376
- });
3377
- return {
3378
- pptxData: ctx.pptxData,
3379
- dirty: true,
3380
- result: { newSlideIndex: insertIndex, slideCount: slides.length }
3381
- };
3382
- }
3383
- function updateSlideProperties(ctx, params) {
3384
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3385
- if (err) {
3386
- throw new Error(err);
3387
- }
3388
- const slide = ctx.pptxData.slides[params.slideIndex];
3389
- if (params.backgroundColor !== void 0) {
3390
- slide.backgroundColor = params.backgroundColor;
3391
- }
3392
- if (params.backgroundGradient !== void 0) {
3393
- slide.backgroundGradient = params.backgroundGradient;
3394
- }
3395
- if (params.backgroundImage !== void 0) {
3396
- slide.backgroundImage = params.backgroundImage;
3397
- }
3398
- if (params.notes !== void 0) {
3399
- slide.notes = params.notes;
3400
- }
3401
- if (params.hidden !== void 0) {
3402
- slide.hidden = params.hidden;
3403
- }
3404
- return {
3405
- pptxData: ctx.pptxData,
3406
- dirty: true,
3407
- result: { slideIndex: params.slideIndex }
3408
- };
3409
- }
3410
- function setSlideTransition(ctx, params) {
3411
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3412
- if (err) {
3413
- throw new Error(err);
3414
- }
3415
- const slide = ctx.pptxData.slides[params.slideIndex];
3416
- if (params.type === "none") {
3417
- slide.transition = void 0;
3418
- } else {
3419
- const transition = {
3420
- type: params.type
3421
- };
3422
- if (params.durationMs !== void 0) {
3423
- transition.durationMs = params.durationMs;
3424
- }
3425
- if (params.direction !== void 0) {
3426
- transition.direction = params.direction;
3427
- }
3428
- if (params.advanceOnClick !== void 0) {
3429
- transition.advanceOnClick = params.advanceOnClick;
3430
- }
3431
- if (params.advanceAfterMs !== void 0) {
3432
- transition.advanceAfterMs = params.advanceAfterMs;
3433
- }
3434
- slide.transition = transition;
3435
- }
3436
- return {
3437
- pptxData: ctx.pptxData,
3438
- dirty: true,
3439
- result: { slideIndex: params.slideIndex, transitionType: params.type }
3440
- };
3441
- }
3442
- function setCanvasSize(ctx, params) {
3443
- ctx.pptxData.width = params.width;
3444
- ctx.pptxData.height = params.height;
3445
- if (ctx.pptxData.widthEmu !== void 0) {
3446
- ctx.pptxData.widthEmu = Math.round(params.width * 12700);
3447
- }
3448
- if (ctx.pptxData.heightEmu !== void 0) {
3449
- ctx.pptxData.heightEmu = Math.round(params.height * 12700);
3450
- }
3451
- return {
3452
- pptxData: ctx.pptxData,
3453
- dirty: true,
3454
- result: { canvasWidth: params.width, canvasHeight: params.height }
3455
- };
3456
- }
3457
- function extractNodes(data) {
3458
- if (!data.nodes) {
3459
- return [];
3460
- }
3461
- return data.nodes.map((n) => ({
3462
- id: n.id,
3463
- text: n.text ?? "",
3464
- children: n.children?.map((c) => ({ id: c.id, text: c.text ?? "" }))
3465
- }));
3466
- }
3467
- function manageSmartArt(ctx, params) {
3468
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3469
- if (err) {
3470
- throw new Error(err);
3471
- }
3472
- const slide = ctx.pptxData.slides[params.slideIndex];
3473
- const el = slide.elements.find((e) => e.id === params.elementId);
3474
- if (!el) {
3475
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
3476
- }
3477
- if (el.type !== "smartArt") {
3478
- throw new Error(`Element '${params.elementId}' is not a SmartArt.`);
3479
- }
3480
- const smartArt = el;
3481
- if (!smartArt.smartArtData) {
3482
- throw new Error(`SmartArt '${params.elementId}' has no data.`);
3483
- }
3484
- switch (params.action) {
3485
- case "getNodes": {
3486
- return {
3487
- pptxData: ctx.pptxData,
3488
- dirty: false,
3489
- result: {
3490
- action: "getNodes",
3491
- elementId: params.elementId,
3492
- nodes: extractNodes(smartArt.smartArtData)
3493
- }
3494
- };
3495
- }
3496
- case "addNode": {
3497
- smartArt.smartArtData = pptxViewerCore.addSmartArtNode(
3498
- smartArt.smartArtData,
3499
- params.text ?? "",
3500
- params.afterNodeId
3501
- );
3502
- return {
3503
- pptxData: ctx.pptxData,
3504
- dirty: true,
3505
- result: {
3506
- action: "addNode",
3507
- elementId: params.elementId,
3508
- nodes: extractNodes(smartArt.smartArtData)
3509
- }
3510
- };
3511
- }
3512
- case "removeNode": {
3513
- if (!params.nodeId) {
3514
- throw new Error("nodeId is required for removeNode.");
3515
- }
3516
- smartArt.smartArtData = pptxViewerCore.removeSmartArtNode(smartArt.smartArtData, params.nodeId);
3517
- return {
3518
- pptxData: ctx.pptxData,
3519
- dirty: true,
3520
- result: {
3521
- action: "removeNode",
3522
- elementId: params.elementId,
3523
- nodes: extractNodes(smartArt.smartArtData)
3524
- }
3525
- };
3526
- }
3527
- case "updateNodeText": {
3528
- if (!params.nodeId) {
3529
- throw new Error("nodeId is required for updateNodeText.");
3530
- }
3531
- smartArt.smartArtData = pptxViewerCore.updateSmartArtNodeText(
3532
- smartArt.smartArtData,
3533
- params.nodeId,
3534
- params.text ?? ""
3535
- );
3536
- return {
3537
- pptxData: ctx.pptxData,
3538
- dirty: true,
3539
- result: { action: "updateNodeText", elementId: params.elementId }
3540
- };
3541
- }
3542
- case "reorderNode": {
3543
- if (!params.nodeId) {
3544
- throw new Error("nodeId is required for reorderNode.");
3545
- }
3546
- const dir = params.direction ?? 1;
3547
- smartArt.smartArtData = pptxViewerCore.reorderSmartArtNode(smartArt.smartArtData, params.nodeId, dir);
3548
- return {
3549
- pptxData: ctx.pptxData,
3550
- dirty: true,
3551
- result: {
3552
- action: "reorderNode",
3553
- elementId: params.elementId,
3554
- nodes: extractNodes(smartArt.smartArtData)
3555
- }
3556
- };
3557
- }
3558
- case "promoteNode": {
3559
- if (!params.nodeId) {
3560
- throw new Error("nodeId is required for promoteNode.");
3561
- }
3562
- smartArt.smartArtData = pptxViewerCore.promoteSmartArtNode(smartArt.smartArtData, params.nodeId);
3563
- return {
3564
- pptxData: ctx.pptxData,
3565
- dirty: true,
3566
- result: {
3567
- action: "promoteNode",
3568
- elementId: params.elementId,
3569
- nodes: extractNodes(smartArt.smartArtData)
3570
- }
3571
- };
3572
- }
3573
- case "demoteNode": {
3574
- if (!params.nodeId) {
3575
- throw new Error("nodeId is required for demoteNode.");
3576
- }
3577
- smartArt.smartArtData = pptxViewerCore.demoteSmartArtNode(smartArt.smartArtData, params.nodeId);
3578
- return {
3579
- pptxData: ctx.pptxData,
3580
- dirty: true,
3581
- result: {
3582
- action: "demoteNode",
3583
- elementId: params.elementId,
3584
- nodes: extractNodes(smartArt.smartArtData)
3585
- }
3586
- };
3587
- }
3588
- case "decompose": {
3589
- const bounds = {
3590
- x: smartArt.x,
3591
- y: smartArt.y,
3592
- width: smartArt.width,
3593
- height: smartArt.height
3594
- };
3595
- const decomposed = pptxViewerCore.decomposeSmartArt(smartArt.smartArtData, bounds);
3596
- if (!decomposed || decomposed.length === 0) {
3597
- throw new Error("Failed to decompose SmartArt into shapes.");
3598
- }
3599
- const idx = slide.elements.indexOf(el);
3600
- slide.elements.splice(idx, 1, ...decomposed);
3601
- return {
3602
- pptxData: ctx.pptxData,
3603
- dirty: true,
3604
- result: {
3605
- action: "decompose",
3606
- elementId: params.elementId,
3607
- decomposedCount: decomposed.length
3608
- }
3609
- };
3610
- }
3611
- default:
3612
- throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
3613
- }
3614
- }
3615
- function findTableElement(ctx, slideIndex, elementId) {
3616
- const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
3617
- if (err) {
3618
- throw new Error(err);
3619
- }
3620
- const slide = ctx.pptxData.slides[slideIndex];
3621
- const el = slide.elements.find((e) => e.id === elementId);
3622
- if (!el) {
3623
- throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
3624
- }
3625
- if (el.type !== "table") {
3626
- throw new Error(`Element '${elementId}' is not a table.`);
3627
- }
3628
- return el;
3629
- }
3630
- function tableStyleIdsInUse(ctx) {
3631
- const used = /* @__PURE__ */ new Set();
3632
- for (const slide of ctx.pptxData.slides) {
3633
- for (const el of slide.elements) {
3634
- if (el.type === "table" && el.tableData?.tableStyleId) {
3635
- used.add(pptxViewerCore.normalizeTableStyleGuid(el.tableData.tableStyleId));
3636
- }
3637
- }
3638
- }
3639
- return used;
3640
- }
3641
- function setTableStyleSection(ctx, params) {
3642
- if (!pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
3643
- throw new Error(
3644
- `Unknown table style section '${params.section}'. Valid sections: ${pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
3645
- );
3646
- }
3647
- const map = ctx.pptxData.tableStyleMap ?? {};
3648
- ctx.pptxData.tableStyleMap = map;
3649
- const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
3650
- const entry = map[normalizedId];
3651
- if (!entry) {
3652
- throw new Error(
3653
- `Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
3654
- );
3655
- }
3656
- if (params.styleName !== void 0) {
3657
- entry.styleName = params.styleName;
3658
- }
3659
- const mutableEntry = entry;
3660
- if (params.fill !== void 0) {
3661
- mutableEntry[`${params.section}Fill`] = params.fill;
3662
- }
3663
- if (params.text !== void 0) {
3664
- mutableEntry[`${params.section}Text`] = params.text;
3665
- }
3666
- if (params.borders !== void 0) {
3667
- mutableEntry[`${params.section}Borders`] = params.borders;
3668
- }
3669
- if (params.cell3D !== void 0) {
3670
- mutableEntry[`${params.section}Cell3D`] = params.cell3D;
3671
- }
3672
- return {
3673
- pptxData: ctx.pptxData,
3674
- dirty: true,
3675
- result: { styleId: normalizedId, section: params.section }
3676
- };
3677
- }
3678
- function createTableStyle(ctx, params) {
3679
- const map = ctx.pptxData.tableStyleMap ?? {};
3680
- ctx.pptxData.tableStyleMap = map;
3681
- const basedOn = params.basedOnStyleId ? map[pptxViewerCore.normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
3682
- if (params.basedOnStyleId && !basedOn) {
3683
- throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
3684
- }
3685
- const entry = pptxViewerCore.createTableStyleEntry(map, { styleName: params.styleName, basedOn });
3686
- pptxViewerCore.addTableStyleToMap(map, entry);
3687
- return {
3688
- pptxData: ctx.pptxData,
3689
- dirty: true,
3690
- result: { styleId: entry.styleId },
3691
- ...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
3692
- };
3693
- }
3694
- function deleteTableStyle(ctx, params) {
3695
- const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
3696
- if (!params.force) {
3697
- const used = tableStyleIdsInUse(ctx);
3698
- if (used.has(normalizedId)) {
3699
- throw new Error(
3700
- `Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
3701
- );
3702
- }
3703
- }
3704
- const map = ctx.pptxData.tableStyleMap ?? {};
3705
- ctx.pptxData.tableStyleMap = map;
3706
- pptxViewerCore.deleteTableStyleFromMap(map, normalizedId);
3707
- return {
3708
- pptxData: ctx.pptxData,
3709
- dirty: true,
3710
- result: { deleted: true },
3711
- saveOptions: { tableStylesToDelete: [normalizedId] }
3712
- };
3713
- }
3714
- function assignTableStyle(ctx, params) {
3715
- const el = findTableElement(ctx, params.slideIndex, params.elementId);
3716
- if (!el.tableData) {
3717
- throw new Error(`Table '${params.elementId}' has no tableData.`);
3718
- }
3719
- const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
3720
- if (!styleId) {
3721
- throw new Error(
3722
- "styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
3723
- );
3724
- }
3725
- const normalizedId = pptxViewerCore.normalizeTableStyleGuid(styleId);
3726
- el.tableData.tableStyleId = normalizedId;
3727
- if (params.bandedRows !== void 0) {
3728
- el.tableData.bandedRows = params.bandedRows;
3729
- }
3730
- if (params.bandedColumns !== void 0) {
3731
- el.tableData.bandedColumns = params.bandedColumns;
3732
- }
3733
- if (params.firstRowHeader !== void 0) {
3734
- el.tableData.firstRowHeader = params.firstRowHeader;
3735
- }
3736
- if (params.lastRow !== void 0) {
3737
- el.tableData.lastRow = params.lastRow;
3738
- }
3739
- if (params.firstCol !== void 0) {
3740
- el.tableData.firstCol = params.firstCol;
3741
- }
3742
- if (params.lastCol !== void 0) {
3743
- el.tableData.lastCol = params.lastCol;
3744
- }
3745
- return {
3746
- pptxData: ctx.pptxData,
3747
- dirty: true,
3748
- result: { elementId: params.elementId, styleId: normalizedId }
3749
- };
3750
- }
3751
- function updateTableCells(ctx, params) {
3752
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3753
- if (err) {
3754
- throw new Error(err);
3755
- }
3756
- const slide = ctx.pptxData.slides[params.slideIndex];
3757
- const el = slide.elements.find((e) => e.id === params.elementId);
3758
- if (!el) {
3759
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
3760
- }
3761
- if (el.type !== "table") {
3762
- throw new Error(`Element '${params.elementId}' is not a table.`);
3763
- }
3764
- const tbl = el;
3765
- if (!tbl.tableData) {
3766
- throw new Error(`Table '${params.elementId}' has no tableData.`);
3767
- }
3768
- let count = 0;
3769
- for (const cellUpdate of params.cells) {
3770
- const row = tbl.tableData.rows[cellUpdate.row];
3771
- if (!row) {
3772
- throw new Error(
3773
- `Row ${cellUpdate.row} out of range (table has ${tbl.tableData.rows.length} rows).`
3774
- );
3775
- }
3776
- const cell = row.cells[cellUpdate.col];
3777
- if (!cell) {
3778
- throw new Error(`Column ${cellUpdate.col} out of range (row has ${row.cells.length} cells).`);
3779
- }
3780
- cell.text = cellUpdate.text;
3781
- count++;
3782
- }
3783
- return {
3784
- pptxData: ctx.pptxData,
3785
- dirty: true,
3786
- result: { updatedCount: count }
3787
- };
3788
- }
3789
- function manageTableStructure(ctx, params) {
3790
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
3791
- if (err) {
3792
- throw new Error(err);
3793
- }
3794
- const slide = ctx.pptxData.slides[params.slideIndex];
3795
- const el = slide.elements.find((e) => e.id === params.elementId);
3796
- if (!el) {
3797
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
3798
- }
3799
- if (el.type !== "table") {
3800
- throw new Error(`Element '${params.elementId}' is not a table.`);
3801
- }
3802
- const tbl = el;
3803
- if (!tbl.tableData) {
3804
- throw new Error(`Table '${params.elementId}' has no tableData.`);
3805
- }
3806
- const { rows, columnWidths } = tbl.tableData;
3807
- const source = { ...tbl, tableData: structuredClone(tbl.tableData) };
3808
- let edit;
3809
- const colCount = columnWidths.length;
3810
- const rowCount = rows.length;
3811
- switch (params.action) {
3812
- case "insertRow": {
3813
- const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), rowCount) : rowCount;
3814
- const newRow = {
3815
- height: 40,
3816
- cells: Array.from({ length: colCount }, (_, c) => ({
3817
- text: params.cellTexts?.[c] ?? ""
3818
- }))
3819
- };
3820
- rows.splice(pos, 0, newRow);
3821
- edit = { axis: "row", action: "insert", index: pos };
3822
- break;
3823
- }
3824
- case "deleteRow": {
3825
- if (rowCount <= 1) {
3826
- throw new Error("Cannot delete the last row of a table.");
3827
- }
3828
- const ref = params.referenceIndex ?? rowCount - 1;
3829
- if (ref < 0 || ref >= rowCount) {
3830
- throw new Error(`Row index ${ref} out of range (0\u2013${rowCount - 1}).`);
3831
- }
3832
- rows.splice(ref, 1);
3833
- edit = { axis: "row", action: "delete", index: ref };
3834
- break;
3835
- }
3836
- case "insertColumn": {
3837
- const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), colCount) : colCount;
3838
- const newWidth = 1 / (colCount + 1);
3839
- const scaleFactor = colCount / (colCount + 1);
3840
- for (let i = 0; i < columnWidths.length; i++) {
3841
- columnWidths[i] *= scaleFactor;
3842
- }
3843
- columnWidths.splice(pos, 0, newWidth);
3844
- edit = { axis: "column", action: "insert", index: pos };
3845
- for (let r = 0; r < rows.length; r++) {
3846
- rows[r].cells.splice(pos, 0, {
3847
- text: params.cellTexts?.[r] ?? ""
3848
- });
3849
- }
3850
- break;
3851
- }
3852
- case "deleteColumn": {
3853
- if (colCount <= 1) {
3854
- throw new Error("Cannot delete the last column of a table.");
3855
- }
3856
- const ref = params.referenceIndex ?? colCount - 1;
3857
- if (ref < 0 || ref >= colCount) {
3858
- throw new Error(`Column index ${ref} out of range (0\u2013${colCount - 1}).`);
3859
- }
3860
- const removedWidth = columnWidths[ref];
3861
- columnWidths.splice(ref, 1);
3862
- edit = { axis: "column", action: "delete", index: ref };
3863
- const remaining = columnWidths.length;
3864
- if (remaining > 0) {
3865
- const extra = removedWidth / remaining;
3866
- for (let i = 0; i < columnWidths.length; i++) {
3867
- columnWidths[i] += extra;
3868
- }
3869
- }
3870
- for (const row of rows) {
3871
- row.cells.splice(ref, 1);
3872
- }
3873
- break;
3874
- }
3875
- default: {
3876
- throw new Error(`Unknown action: ${String(params.action)}`);
3877
- }
3878
- }
3879
- const rawXml = pptxViewerCore.rebuildTableStructureInRawXml(source, tbl.tableData, edit);
3880
- if (rawXml) {
3881
- tbl.rawXml = rawXml;
3882
- }
3883
- return {
3884
- pptxData: ctx.pptxData,
3885
- dirty: true,
3886
- result: {
3887
- rowCount: tbl.tableData.rows.length,
3888
- columnCount: tbl.tableData.columnWidths.length
3889
- }
3890
- };
3891
- }
3892
- function findPlaceholdersT(ctx) {
3893
- const placeholders = pptxViewerCore.findPlaceholders(ctx.pptxData);
3894
- return {
3895
- pptxData: ctx.pptxData,
3896
- dirty: false,
3897
- result: { placeholders, count: placeholders.length }
3898
- };
3899
- }
3900
- function applyTemplateT(ctx, params) {
3901
- pptxViewerCore.applyTemplate(ctx.pptxData, params.data);
3902
- return {
3903
- pptxData: ctx.pptxData,
3904
- dirty: true,
3905
- result: { applied: true, slideCount: ctx.pptxData.slides.length }
3906
- };
3907
- }
3908
- function getThemeInfo(ctx) {
3909
- const theme = ctx.pptxData.theme;
3910
- return {
3911
- pptxData: ctx.pptxData,
3912
- dirty: false,
3913
- result: {
3914
- themeName: theme?.name,
3915
- colorScheme: theme?.colorScheme,
3916
- fontScheme: theme?.fontScheme,
3917
- availablePresets: Object.keys(pptxViewerCore.ThemePresets)
3918
- }
3919
- };
3920
- }
3921
- function applyThemePreset(ctx, params) {
3922
- const preset = pptxViewerCore.getThemePreset(params.presetName);
3923
- if (!preset) {
3924
- throw new Error(
3925
- `Unknown theme preset: "${params.presetName}". Available: ${Object.keys(pptxViewerCore.ThemePresets).join(", ")}`
3926
- );
3927
- }
3928
- if (!ctx.pptxData.theme) {
3929
- ctx.pptxData.theme = {};
3930
- }
3931
- const theme = ctx.pptxData.theme;
3932
- theme.name = preset.name;
3933
- theme.colorScheme = preset.colors;
3934
- if (preset.fonts) {
3935
- theme.fontScheme = preset.fonts;
3936
- }
3937
- return {
3938
- pptxData: ctx.pptxData,
3939
- dirty: true,
3940
- result: {
3941
- appliedPreset: params.presetName,
3942
- colorScheme: theme.colorScheme
3943
- }
3944
- };
3945
- }
3946
- function updateThemeColors(ctx, params) {
3947
- if (!ctx.pptxData.theme) {
3948
- ctx.pptxData.theme = {};
3949
- }
3950
- const theme = ctx.pptxData.theme;
3951
- if (!theme.colorScheme) {
3952
- theme.colorScheme = {
3953
- dk1: "#000000",
3954
- lt1: "#FFFFFF",
3955
- dk2: "#44546A",
3956
- lt2: "#E7E6E6",
3957
- accent1: "#4472C4",
3958
- accent2: "#ED7D31",
3959
- accent3: "#A5A5A5",
3960
- accent4: "#FFC000",
3961
- accent5: "#5B9BD5",
3962
- accent6: "#70AD47",
3963
- hlink: "#0563C1",
3964
- folHlink: "#954F72"
3965
- };
3966
- }
3967
- const cs = theme.colorScheme;
3968
- for (const key of Object.keys(params)) {
3969
- if (params[key] !== void 0) {
3970
- cs[key] = params[key];
3971
- }
3972
- }
3973
- return {
3974
- pptxData: ctx.pptxData,
3975
- dirty: true,
3976
- result: { colorScheme: cs }
3977
- };
3978
- }
3979
- function updateThemeFonts(ctx, params) {
3980
- if (!ctx.pptxData.theme) {
3981
- ctx.pptxData.theme = {};
3982
- }
3983
- const theme = ctx.pptxData.theme;
3984
- if (!theme.fontScheme) {
3985
- theme.fontScheme = {};
3986
- }
3987
- if (params.majorFont !== void 0) {
3988
- theme.fontScheme.majorFont = { latin: params.majorFont };
3989
- }
3990
- if (params.minorFont !== void 0) {
3991
- theme.fontScheme.minorFont = { latin: params.minorFont };
3992
- }
3993
- return {
3994
- pptxData: ctx.pptxData,
3995
- dirty: true,
3996
- result: { fontScheme: theme.fontScheme }
3997
- };
3998
- }
3999
- async function validatePresentation(rawBytes) {
4000
- const result = await pptxViewerCore.validatePptx(rawBytes);
4001
- return {
4002
- valid: result.valid,
4003
- issueCount: result.issues.length,
4004
- errors: result.issues.filter((i) => i.severity === "error").length,
4005
- warnings: result.issues.filter((i) => i.severity === "warning").length,
4006
- issues: result.issues
4007
- };
4008
- }
4009
- async function repairPresentation(rawBytes) {
4010
- const result = await pptxViewerCore.repairPptx(rawBytes);
4011
- return {
4012
- result: {
4013
- repairCount: result.repairs.length,
4014
- repairs: result.repairs
4015
- },
4016
- repairedBytes: result.repaired
4017
- };
4018
- }
4019
- var PPTX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
4020
- async function loadPresentation(filePath, execCtx) {
4021
- const rawBytes = await execCtx.filesystem.readFile(filePath);
4022
- if (execCtx.collaboration) {
4023
- const room = execCtx.collaboration.getRoom(filePath);
4024
- if (room) {
4025
- const codec = execCtx.collaboration.getCodec(filePath);
4026
- if (codec) {
4027
- const currentBytes = await codec.dehydrate(room.ydoc);
4028
- const handler2 = new pptxViewerCore.PptxHandler();
4029
- const pptxData2 = await handler2.load(currentBytes.buffer);
4030
- return { pptxData: pptxData2, rawBytes };
4031
- }
4032
- }
4033
- }
4034
- const handler = new pptxViewerCore.PptxHandler();
4035
- const pptxData = await handler.load(rawBytes.buffer);
4036
- return { pptxData, rawBytes };
4037
- }
4038
- async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
4039
- const handler = new pptxViewerCore.PptxHandler();
4040
- await handler.load(rawBytes.buffer);
4041
- const outputBytes = await handler.save(pptxData.slides, {
4042
- headerFooter: pptxData.headerFooter,
4043
- // `pptxData.tableStyleMap` carries any in-memory table-style edits a
4044
- // tool made (e.g. `set_table_style_section`, `create_table_style`);
4045
- // without forwarding it here those edits were silently dropped on
4046
- // save even though the core save pipeline already supports them.
4047
- tableStyles: pptxData.tableStyleMap,
4048
- ...tableStyleSaveOptions
4049
- });
4050
- if (execCtx.collaboration) {
4051
- const room = execCtx.collaboration.getRoom(filePath);
4052
- if (room) {
4053
- const codec = execCtx.collaboration.getCodec(filePath);
4054
- if (codec) {
4055
- const origin = execCtx.collaboration.agentOrigin(execCtx.agentName ?? "pptx-tool");
4056
- await codec.hydrate(room.ydoc, outputBytes, origin);
4057
- if (execCtx.viewer) {
4058
- execCtx.viewer.replaceContent(filePath, outputBytes, {
4059
- markDirty: false,
4060
- mimeType: PPTX_MIME_TYPE
4061
- });
4062
- }
4063
- return { savedToDisk: false, routedThroughCollaboration: true };
4064
- }
4065
- }
4066
- }
4067
- await execCtx.filesystem.writeFile(filePath, outputBytes);
4068
- if (execCtx.viewer) {
4069
- execCtx.viewer.replaceContent(filePath, outputBytes, {
4070
- markDirty: false,
4071
- mimeType: PPTX_MIME_TYPE
4072
- });
4073
- }
4074
- return { savedToDisk: true, routedThroughCollaboration: false };
4075
- }
4076
- async function executeToolWithContext(filePath, execCtx, toolFn) {
4077
- const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
4078
- const toolResult = await toolFn({ pptxData });
4079
- if (toolResult.dirty) {
4080
- const saveResult = await savePresentation(
4081
- filePath,
4082
- toolResult.pptxData,
4083
- rawBytes,
4084
- execCtx,
4085
- toolResult.saveOptions
4086
- );
4087
- return { ...toolResult.result, ...saveResult };
4088
- }
4089
- return toolResult.result;
4090
- }
934
+ var formatChartDataPoint = automation.apiToolsChartFormattingTools.formatChartDataPoint;
935
+ var formatChartDataLabel = automation.apiToolsChartFormattingTools.formatChartDataLabel;
936
+ var formatChartSeries = automation.apiToolsChartFormattingTools.formatChartSeries;
937
+ var setChartHelperLineT = automation.apiToolsChartFormattingTools.setChartHelperLineT;
938
+ var setChartColorMapOverrideT = automation.apiToolsChartFormattingTools.setChartColorMapOverrideT;
939
+ var updateChart = automation.apiToolsChartTools.updateChart;
940
+ var addChartSeriesT = automation.apiToolsChartTools.addChartSeriesT;
941
+ var removeChartSeriesT = automation.apiToolsChartTools.removeChartSeriesT;
942
+ var updateChartSeriesData = automation.apiToolsChartTools.updateChartSeriesData;
943
+ var createChart = automation.apiToolsChartTools.createChart;
944
+ var listChartUserShapesT = automation.apiToolsChartUserShapeTools.listChartUserShapesT;
945
+ var addChartUserShapeT = automation.apiToolsChartUserShapeTools.addChartUserShapeT;
946
+ var updateChartUserShapeT = automation.apiToolsChartUserShapeTools.updateChartUserShapeT;
947
+ var removeChartUserShapeT = automation.apiToolsChartUserShapeTools.removeChartUserShapeT;
948
+ var findText = automation.apiToolsContentTools.findText;
949
+ var replaceText = automation.apiToolsContentTools.replaceText;
950
+ var manageComments = automation.apiToolsContentTools.manageComments;
951
+ var convertToMarkdown = automation.apiToolsConversionTools.convertToMarkdown;
952
+ var addElement = automation.apiToolsElementTools.addElement;
953
+ var updateElement = automation.apiToolsElementTools.updateElement;
954
+ var renameElement = automation.apiToolsElementTools.renameElement;
955
+ var deleteElements = automation.apiToolsElementTools.deleteElements;
956
+ var arrangeElements = automation.apiToolsElementTools.arrangeElements;
957
+ var cloneElement = automation.apiToolsElementTools.cloneElement;
958
+ var setElementAnimation = automation.apiToolsElementTools.setElementAnimation;
959
+ var groupElements = automation.apiToolsElementTools.groupElements;
960
+ var ungroupElements = automation.apiToolsElementTools.ungroupElements;
961
+ var batchUpdateElements = automation.apiToolsElementTools.batchUpdateElements;
962
+ var exportToSvg = automation.apiToolsExportTools.exportToSvg;
963
+ var exportSlideSvg = automation.apiToolsExportTools.exportSlideSvg;
964
+ var replaceGeometry = automation.apiToolsGeometryTools.replaceGeometry;
965
+ var manageHyperlinks = automation.apiToolsHyperlinkTools.manageHyperlinks;
966
+ var exportToJson = automation.apiToolsJsonTools.exportToJson;
967
+ var importFromJson = automation.apiToolsJsonTools.importFromJson;
968
+ var getLayouts = automation.apiToolsLayoutTools.getLayouts;
969
+ var applyLayout = automation.apiToolsLayoutTools.applyLayout;
970
+ var setElementLockT = automation.apiToolsLockTools.setElementLockT;
971
+ var getMetadata = automation.apiToolsMetadataTools.getMetadata;
972
+ var updateMetadata = automation.apiToolsMetadataTools.updateMetadata;
973
+ var getOleContent = automation.apiToolsOleTools.getOleContent;
974
+ var setOleSheetCell = automation.apiToolsOleTools.setOleSheetCell;
975
+ var setOleDocumentParagraph = automation.apiToolsOleTools.setOleDocumentParagraph;
976
+ var setOleDeckSlideTitle = automation.apiToolsOleTools.setOleDeckSlideTitle;
977
+ var setOleObjectNameT = automation.apiToolsOleTools.setOleObjectNameT;
978
+ var replaceOleFileT = automation.apiToolsOleTools.replaceOleFileT;
979
+ var getPresentationProperties = automation.apiToolsPresentationTools.getPresentationProperties;
980
+ var updatePresentationProperties = automation.apiToolsPresentationTools.updatePresentationProperties;
981
+ var manageSections = automation.apiToolsSectionTools.manageSections;
982
+ var getSlide = automation.apiToolsSlideTools.getSlide;
983
+ var addSlide = automation.apiToolsSlideTools.addSlide;
984
+ var deleteSlides = automation.apiToolsSlideTools.deleteSlides;
985
+ var reorderSlides = automation.apiToolsSlideTools.reorderSlides;
986
+ var duplicateSlide = automation.apiToolsSlideTools.duplicateSlide;
987
+ var updateSlideProperties = automation.apiToolsSlideTools.updateSlideProperties;
988
+ var setSlideTransition = automation.apiToolsSlideTools.setSlideTransition;
989
+ var setCanvasSize = automation.apiToolsSlideTools.setCanvasSize;
990
+ var manageSmartArt = automation.apiToolsSmartartTools.manageSmartArt;
991
+ automation.apiToolsStyleTools.ALT_TEXT_ELEMENT_TYPES;
992
+ automation.apiToolsStyleTools.TITLE_ELEMENT_TYPES;
993
+ automation.apiToolsStyleTools.applyElementAltText;
994
+ automation.apiToolsStyleTools.applyElementTitle;
995
+ var updateElementStyle = automation.apiToolsStyleTools.updateElementStyle;
996
+ var runAccessibilityCheck = automation.apiToolsStyleTools.runAccessibilityCheck;
997
+ var setTableStyleSection = automation.apiToolsTableStyleTools.setTableStyleSection;
998
+ var createTableStyle = automation.apiToolsTableStyleTools.createTableStyle;
999
+ var deleteTableStyle = automation.apiToolsTableStyleTools.deleteTableStyle;
1000
+ var assignTableStyle = automation.apiToolsTableStyleTools.assignTableStyle;
1001
+ var updateTableCells = automation.apiToolsTableTools.updateTableCells;
1002
+ var manageTableStructure = automation.apiToolsTableTools.manageTableStructure;
1003
+ var findPlaceholdersT = automation.apiToolsTemplateTools.findPlaceholdersT;
1004
+ var applyTemplateT = automation.apiToolsTemplateTools.applyTemplateT;
1005
+ var getThemeInfo = automation.apiToolsThemeTools.getThemeInfo;
1006
+ var applyThemePreset = automation.apiToolsThemeTools.applyThemePreset;
1007
+ var updateThemeColors = automation.apiToolsThemeTools.updateThemeColors;
1008
+ var updateThemeFonts = automation.apiToolsThemeTools.updateThemeFonts;
1009
+ var validatePresentation = automation.apiToolsValidationTools.validatePresentation;
1010
+ var repairPresentation = automation.apiToolsValidationTools.repairPresentation;
1011
+ automation.apiExecution.loadPresentation;
1012
+ automation.apiExecution.savePresentation;
1013
+ var executeToolWithContext = automation.apiExecution.executeToolWithContext;
4091
1014
 
4092
1015
  // src/mcp/handlers.ts
4093
1016
  var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".pptx", ".ppt"]);
@@ -4139,19 +1062,26 @@ async function runMcpTool(filePath, fn, options) {
4139
1062
  }
4140
1063
 
4141
1064
  // src/mcp/server.ts
4142
- function createServer() {
4143
- const server2 = new mcp_js.McpServer({
1065
+ function createServer(options) {
1066
+ const server = new mcp_js.McpServer({
4144
1067
  name: "pptx-viewer-tools",
4145
1068
  version: "1.0.0"
4146
1069
  });
4147
- server2.registerTool(
1070
+ registerTools(server, options);
1071
+ return server;
1072
+ }
1073
+ function registerTools(server, options) {
1074
+ const runMcpTool2 = (filePath, fn) => runMcpTool(filePath, fn, options);
1075
+ const resolveScopedDir2 = (dir) => resolveScopedDir(dir, options?.rootDir);
1076
+ const resolveScopedFilePath2 = (filePath) => resolveScopedFilePath(filePath, options?.rootDir);
1077
+ server.registerTool(
4148
1078
  "get_slide",
4149
1079
  {
4150
1080
  description: "Inspect a single slide: returns layout, notes, elements",
4151
1081
  inputSchema: GetSlideSchema.shape
4152
1082
  },
4153
1083
  async (params) => {
4154
- const result = await runMcpTool(
1084
+ const result = await runMcpTool2(
4155
1085
  params.filePath,
4156
1086
  (ctx) => getSlide(ctx, { slideIndex: params.slideIndex })
4157
1087
  );
@@ -4165,14 +1095,14 @@ function createServer() {
4165
1095
  };
4166
1096
  }
4167
1097
  );
4168
- server2.registerTool(
1098
+ server.registerTool(
4169
1099
  "add_slide",
4170
1100
  {
4171
1101
  description: "Add a new blank slide to the presentation",
4172
1102
  inputSchema: AddSlideSchema.shape
4173
1103
  },
4174
1104
  async (params) => {
4175
- const result = await runMcpTool(params.filePath, (ctx) => addSlide(ctx, params));
1105
+ const result = await runMcpTool2(params.filePath, (ctx) => addSlide(ctx, params));
4176
1106
  return {
4177
1107
  content: [
4178
1108
  {
@@ -4183,14 +1113,14 @@ function createServer() {
4183
1113
  };
4184
1114
  }
4185
1115
  );
4186
- server2.registerTool(
1116
+ server.registerTool(
4187
1117
  "delete_slides",
4188
1118
  {
4189
1119
  description: "Delete one or more slides by index",
4190
1120
  inputSchema: DeleteSlidesSchema.shape
4191
1121
  },
4192
1122
  async (params) => {
4193
- const result = await runMcpTool(
1123
+ const result = await runMcpTool2(
4194
1124
  params.filePath,
4195
1125
  (ctx) => deleteSlides(ctx, {
4196
1126
  slideIndexes: params.slideIndexes
@@ -4206,14 +1136,14 @@ function createServer() {
4206
1136
  };
4207
1137
  }
4208
1138
  );
4209
- server2.registerTool(
1139
+ server.registerTool(
4210
1140
  "reorder_slides",
4211
1141
  {
4212
1142
  description: "Reorder slides by providing a new index array",
4213
1143
  inputSchema: ReorderSlidesSchema.shape
4214
1144
  },
4215
1145
  async (params) => {
4216
- const result = await runMcpTool(
1146
+ const result = await runMcpTool2(
4217
1147
  params.filePath,
4218
1148
  (ctx) => reorderSlides(ctx, { newOrder: params.newOrder })
4219
1149
  );
@@ -4227,14 +1157,14 @@ function createServer() {
4227
1157
  };
4228
1158
  }
4229
1159
  );
4230
- server2.registerTool(
1160
+ server.registerTool(
4231
1161
  "duplicate_slide",
4232
1162
  {
4233
1163
  description: "Duplicate a slide with new element IDs",
4234
1164
  inputSchema: DuplicateSlideSchema.shape
4235
1165
  },
4236
1166
  async (params) => {
4237
- const result = await runMcpTool(
1167
+ const result = await runMcpTool2(
4238
1168
  params.filePath,
4239
1169
  (ctx) => duplicateSlide(ctx, params)
4240
1170
  );
@@ -4248,14 +1178,14 @@ function createServer() {
4248
1178
  };
4249
1179
  }
4250
1180
  );
4251
- server2.registerTool(
1181
+ server.registerTool(
4252
1182
  "update_slide_properties",
4253
1183
  {
4254
1184
  description: "Update slide background, notes, or visibility",
4255
1185
  inputSchema: UpdateSlidePropertiesSchema.shape
4256
1186
  },
4257
1187
  async (params) => {
4258
- const result = await runMcpTool(
1188
+ const result = await runMcpTool2(
4259
1189
  params.filePath,
4260
1190
  (ctx) => updateSlideProperties(ctx, params)
4261
1191
  );
@@ -4269,14 +1199,14 @@ function createServer() {
4269
1199
  };
4270
1200
  }
4271
1201
  );
4272
- server2.registerTool(
1202
+ server.registerTool(
4273
1203
  "set_slide_transition",
4274
1204
  {
4275
1205
  description: "Set or remove a slide transition effect",
4276
1206
  inputSchema: SetSlideTransitionSchema.shape
4277
1207
  },
4278
1208
  async (params) => {
4279
- const result = await runMcpTool(
1209
+ const result = await runMcpTool2(
4280
1210
  params.filePath,
4281
1211
  (ctx) => setSlideTransition(ctx, params)
4282
1212
  );
@@ -4290,14 +1220,14 @@ function createServer() {
4290
1220
  };
4291
1221
  }
4292
1222
  );
4293
- server2.registerTool(
1223
+ server.registerTool(
4294
1224
  "set_canvas_size",
4295
1225
  {
4296
1226
  description: "Change the presentation canvas dimensions",
4297
1227
  inputSchema: SetCanvasSizeSchema.shape
4298
1228
  },
4299
1229
  async (params) => {
4300
- const result = await runMcpTool(
1230
+ const result = await runMcpTool2(
4301
1231
  params.filePath,
4302
1232
  (ctx) => setCanvasSize(ctx, params)
4303
1233
  );
@@ -4311,14 +1241,14 @@ function createServer() {
4311
1241
  };
4312
1242
  }
4313
1243
  );
4314
- server2.registerTool(
1244
+ server.registerTool(
4315
1245
  "add_element",
4316
1246
  {
4317
1247
  description: "Add a text, shape, image, table, or connector element",
4318
1248
  inputSchema: AddElementSchema.shape
4319
1249
  },
4320
1250
  async (params) => {
4321
- const result = await runMcpTool(
1251
+ const result = await runMcpTool2(
4322
1252
  params.filePath,
4323
1253
  (ctx) => addElement(ctx, params)
4324
1254
  );
@@ -4332,14 +1262,14 @@ function createServer() {
4332
1262
  };
4333
1263
  }
4334
1264
  );
4335
- server2.registerTool(
1265
+ server.registerTool(
4336
1266
  "update_element",
4337
1267
  {
4338
1268
  description: "Update element position, size, text, or style",
4339
1269
  inputSchema: UpdateElementSchema.shape
4340
1270
  },
4341
1271
  async (params) => {
4342
- const result = await runMcpTool(
1272
+ const result = await runMcpTool2(
4343
1273
  params.filePath,
4344
1274
  (ctx) => updateElement(ctx, params)
4345
1275
  );
@@ -4353,14 +1283,14 @@ function createServer() {
4353
1283
  };
4354
1284
  }
4355
1285
  );
4356
- server2.registerTool(
1286
+ server.registerTool(
4357
1287
  "rename_element",
4358
1288
  {
4359
1289
  description: "Rename an element (the selection pane's display name; cNvPr/@name)",
4360
1290
  inputSchema: RenameElementSchema.shape
4361
1291
  },
4362
1292
  async (params) => {
4363
- const result = await runMcpTool(
1293
+ const result = await runMcpTool2(
4364
1294
  params.filePath,
4365
1295
  (ctx) => renameElement(ctx, params)
4366
1296
  );
@@ -4374,14 +1304,14 @@ function createServer() {
4374
1304
  };
4375
1305
  }
4376
1306
  );
4377
- server2.registerTool(
1307
+ server.registerTool(
4378
1308
  "delete_elements",
4379
1309
  {
4380
1310
  description: "Delete one or more elements by ID",
4381
1311
  inputSchema: DeleteElementsSchema.shape
4382
1312
  },
4383
1313
  async (params) => {
4384
- const result = await runMcpTool(
1314
+ const result = await runMcpTool2(
4385
1315
  params.filePath,
4386
1316
  (ctx) => deleteElements(ctx, params)
4387
1317
  );
@@ -4395,14 +1325,14 @@ function createServer() {
4395
1325
  };
4396
1326
  }
4397
1327
  );
4398
- server2.registerTool(
1328
+ server.registerTool(
4399
1329
  "arrange_elements",
4400
1330
  {
4401
1331
  description: "Align elements or change z-order (layer)",
4402
1332
  inputSchema: ArrangeElementsSchema.shape
4403
1333
  },
4404
1334
  async (params) => {
4405
- const result = await runMcpTool(
1335
+ const result = await runMcpTool2(
4406
1336
  params.filePath,
4407
1337
  (ctx) => arrangeElements(ctx, params)
4408
1338
  );
@@ -4416,14 +1346,14 @@ function createServer() {
4416
1346
  };
4417
1347
  }
4418
1348
  );
4419
- server2.registerTool(
1349
+ server.registerTool(
4420
1350
  "clone_element",
4421
1351
  {
4422
1352
  description: "Clone an element within or across slides",
4423
1353
  inputSchema: CloneElementSchema.shape
4424
1354
  },
4425
1355
  async (params) => {
4426
- const result = await runMcpTool(
1356
+ const result = await runMcpTool2(
4427
1357
  params.filePath,
4428
1358
  (ctx) => cloneElement(ctx, params)
4429
1359
  );
@@ -4437,14 +1367,14 @@ function createServer() {
4437
1367
  };
4438
1368
  }
4439
1369
  );
4440
- server2.registerTool(
1370
+ server.registerTool(
4441
1371
  "set_element_animation",
4442
1372
  {
4443
1373
  description: "Set entrance/exit animation on an element",
4444
1374
  inputSchema: SetElementAnimationSchema.shape
4445
1375
  },
4446
1376
  async (params) => {
4447
- const result = await runMcpTool(
1377
+ const result = await runMcpTool2(
4448
1378
  params.filePath,
4449
1379
  (ctx) => setElementAnimation(ctx, params)
4450
1380
  );
@@ -4458,14 +1388,14 @@ function createServer() {
4458
1388
  };
4459
1389
  }
4460
1390
  );
4461
- server2.registerTool(
1391
+ server.registerTool(
4462
1392
  "group_elements",
4463
1393
  {
4464
1394
  description: "Group multiple elements into a group",
4465
1395
  inputSchema: GroupElementsSchema.shape
4466
1396
  },
4467
1397
  async (params) => {
4468
- const result = await runMcpTool(
1398
+ const result = await runMcpTool2(
4469
1399
  params.filePath,
4470
1400
  (ctx) => groupElements(ctx, params)
4471
1401
  );
@@ -4479,14 +1409,14 @@ function createServer() {
4479
1409
  };
4480
1410
  }
4481
1411
  );
4482
- server2.registerTool(
1412
+ server.registerTool(
4483
1413
  "ungroup_elements",
4484
1414
  {
4485
1415
  description: "Ungroup a group element back to individual elements",
4486
1416
  inputSchema: UngroupElementsSchema.shape
4487
1417
  },
4488
1418
  async (params) => {
4489
- const result = await runMcpTool(
1419
+ const result = await runMcpTool2(
4490
1420
  params.filePath,
4491
1421
  (ctx) => ungroupElements(ctx, params)
4492
1422
  );
@@ -4500,14 +1430,14 @@ function createServer() {
4500
1430
  };
4501
1431
  }
4502
1432
  );
4503
- server2.registerTool(
1433
+ server.registerTool(
4504
1434
  "batch_update_elements",
4505
1435
  {
4506
1436
  description: "Apply the same properties to multiple elements",
4507
1437
  inputSchema: BatchUpdateElementsSchema.shape
4508
1438
  },
4509
1439
  async (params) => {
4510
- const result = await runMcpTool(
1440
+ const result = await runMcpTool2(
4511
1441
  params.filePath,
4512
1442
  (ctx) => batchUpdateElements(ctx, params)
4513
1443
  );
@@ -4521,14 +1451,14 @@ function createServer() {
4521
1451
  };
4522
1452
  }
4523
1453
  );
4524
- server2.registerTool(
1454
+ server.registerTool(
4525
1455
  "update_table_cells",
4526
1456
  {
4527
1457
  description: "Update text content of table cells",
4528
1458
  inputSchema: UpdateTableCellsSchema.shape
4529
1459
  },
4530
1460
  async (params) => {
4531
- const result = await runMcpTool(
1461
+ const result = await runMcpTool2(
4532
1462
  params.filePath,
4533
1463
  (ctx) => updateTableCells(ctx, params)
4534
1464
  );
@@ -4542,14 +1472,14 @@ function createServer() {
4542
1472
  };
4543
1473
  }
4544
1474
  );
4545
- server2.registerTool(
1475
+ server.registerTool(
4546
1476
  "manage_table_structure",
4547
1477
  {
4548
1478
  description: "Insert or delete table rows and columns",
4549
1479
  inputSchema: ManageTableStructureSchema.shape
4550
1480
  },
4551
1481
  async (params) => {
4552
- const result = await runMcpTool(
1482
+ const result = await runMcpTool2(
4553
1483
  params.filePath,
4554
1484
  (ctx) => manageTableStructure(ctx, params)
4555
1485
  );
@@ -4563,14 +1493,14 @@ function createServer() {
4563
1493
  };
4564
1494
  }
4565
1495
  );
4566
- server2.registerTool(
1496
+ server.registerTool(
4567
1497
  "set_table_style_section",
4568
1498
  {
4569
1499
  description: "Patch the fill, text, borders, or cell3D of one section (wholeTbl, banding, first/last row/col, or a corner cell) of an existing loaded table style",
4570
1500
  inputSchema: SetTableStyleSectionSchema.shape
4571
1501
  },
4572
1502
  async (params) => {
4573
- const result = await runMcpTool(
1503
+ const result = await runMcpTool2(
4574
1504
  params.filePath,
4575
1505
  (ctx) => setTableStyleSection(ctx, params)
4576
1506
  );
@@ -4579,14 +1509,14 @@ function createServer() {
4579
1509
  };
4580
1510
  }
4581
1511
  );
4582
- server2.registerTool(
1512
+ server.registerTool(
4583
1513
  "create_table_style",
4584
1514
  {
4585
1515
  description: "Create a new table style (optionally cloned from an existing one) and optionally set it as the default",
4586
1516
  inputSchema: CreateTableStyleSchema.shape
4587
1517
  },
4588
1518
  async (params) => {
4589
- const result = await runMcpTool(
1519
+ const result = await runMcpTool2(
4590
1520
  params.filePath,
4591
1521
  (ctx) => createTableStyle(ctx, params)
4592
1522
  );
@@ -4595,14 +1525,14 @@ function createServer() {
4595
1525
  };
4596
1526
  }
4597
1527
  );
4598
- server2.registerTool(
1528
+ server.registerTool(
4599
1529
  "delete_table_style",
4600
1530
  {
4601
1531
  description: "Remove a table style from the presentation",
4602
1532
  inputSchema: DeleteTableStyleSchema.shape
4603
1533
  },
4604
1534
  async (params) => {
4605
- const result = await runMcpTool(
1535
+ const result = await runMcpTool2(
4606
1536
  params.filePath,
4607
1537
  (ctx) => deleteTableStyle(ctx, params)
4608
1538
  );
@@ -4611,14 +1541,14 @@ function createServer() {
4611
1541
  };
4612
1542
  }
4613
1543
  );
4614
- server2.registerTool(
1544
+ server.registerTool(
4615
1545
  "assign_table_style",
4616
1546
  {
4617
1547
  description: "Assign a table style (and row/column emphasis flags) to an existing table",
4618
1548
  inputSchema: AssignTableStyleSchema.shape
4619
1549
  },
4620
1550
  async (params) => {
4621
- const result = await runMcpTool(
1551
+ const result = await runMcpTool2(
4622
1552
  params.filePath,
4623
1553
  (ctx) => assignTableStyle(ctx, params)
4624
1554
  );
@@ -4627,14 +1557,14 @@ function createServer() {
4627
1557
  };
4628
1558
  }
4629
1559
  );
4630
- server2.registerTool(
1560
+ server.registerTool(
4631
1561
  "update_element_style",
4632
1562
  {
4633
1563
  description: "Update fill, stroke, shadow, glow, or image effects",
4634
1564
  inputSchema: UpdateElementStyleSchema.shape
4635
1565
  },
4636
1566
  async (params) => {
4637
- const result = await runMcpTool(
1567
+ const result = await runMcpTool2(
4638
1568
  params.filePath,
4639
1569
  (ctx) => updateElementStyle(ctx, params)
4640
1570
  );
@@ -4648,14 +1578,14 @@ function createServer() {
4648
1578
  };
4649
1579
  }
4650
1580
  );
4651
- server2.registerTool(
1581
+ server.registerTool(
4652
1582
  "run_accessibility_check",
4653
1583
  {
4654
1584
  description: "Audit the presentation for accessibility issues",
4655
1585
  inputSchema: AccessibilityCheckSchema.shape
4656
1586
  },
4657
1587
  async (params) => {
4658
- const result = await runMcpTool(
1588
+ const result = await runMcpTool2(
4659
1589
  params.filePath,
4660
1590
  (ctx) => runAccessibilityCheck(ctx)
4661
1591
  );
@@ -4669,14 +1599,14 @@ function createServer() {
4669
1599
  };
4670
1600
  }
4671
1601
  );
4672
- server2.registerTool(
1602
+ server.registerTool(
4673
1603
  "find_text",
4674
1604
  {
4675
1605
  description: "Search for text across all slides",
4676
1606
  inputSchema: FindTextSchema.shape
4677
1607
  },
4678
1608
  async (params) => {
4679
- const result = await runMcpTool(params.filePath, (ctx) => findText(ctx, params));
1609
+ const result = await runMcpTool2(params.filePath, (ctx) => findText(ctx, params));
4680
1610
  return {
4681
1611
  content: [
4682
1612
  {
@@ -4687,14 +1617,14 @@ function createServer() {
4687
1617
  };
4688
1618
  }
4689
1619
  );
4690
- server2.registerTool(
1620
+ server.registerTool(
4691
1621
  "replace_text",
4692
1622
  {
4693
1623
  description: "Find and replace text across slides",
4694
1624
  inputSchema: ReplaceTextSchema.shape
4695
1625
  },
4696
1626
  async (params) => {
4697
- const result = await runMcpTool(
1627
+ const result = await runMcpTool2(
4698
1628
  params.filePath,
4699
1629
  (ctx) => replaceText(ctx, params)
4700
1630
  );
@@ -4708,14 +1638,14 @@ function createServer() {
4708
1638
  };
4709
1639
  }
4710
1640
  );
4711
- server2.registerTool(
1641
+ server.registerTool(
4712
1642
  "manage_comments",
4713
1643
  {
4714
1644
  description: "List, add, delete, or resolve slide comments",
4715
1645
  inputSchema: ManageCommentsSchema.shape
4716
1646
  },
4717
1647
  async (params) => {
4718
- const result = await runMcpTool(
1648
+ const result = await runMcpTool2(
4719
1649
  params.filePath,
4720
1650
  (ctx) => manageComments(ctx, params)
4721
1651
  );
@@ -4729,16 +1659,16 @@ function createServer() {
4729
1659
  };
4730
1660
  }
4731
1661
  );
4732
- server2.registerTool(
1662
+ server.registerTool(
4733
1663
  "convert_to_markdown",
4734
1664
  {
4735
1665
  description: "Convert the presentation to Markdown format",
4736
1666
  inputSchema: ConvertToMarkdownSchema.shape
4737
1667
  },
4738
1668
  async (params) => {
4739
- const result = await runMcpTool(
1669
+ const result = await runMcpTool2(
4740
1670
  params.filePath,
4741
- (ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir: resolveScopedDir })
1671
+ (ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir: resolveScopedDir2 })
4742
1672
  );
4743
1673
  return {
4744
1674
  content: [
@@ -4750,414 +1680,414 @@ function createServer() {
4750
1680
  };
4751
1681
  }
4752
1682
  );
4753
- server2.registerTool(
1683
+ server.registerTool(
4754
1684
  "get_theme_info",
4755
1685
  {
4756
1686
  description: "Get current theme information (colors, fonts, available presets)",
4757
1687
  inputSchema: GetThemeInfoSchema.shape
4758
1688
  },
4759
1689
  async (params) => {
4760
- const result = await runMcpTool(params.filePath, (ctx) => getThemeInfo(ctx));
1690
+ const result = await runMcpTool2(params.filePath, (ctx) => getThemeInfo(ctx));
4761
1691
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4762
1692
  }
4763
1693
  );
4764
- server2.registerTool(
1694
+ server.registerTool(
4765
1695
  "apply_theme_preset",
4766
1696
  {
4767
1697
  description: "Apply a built-in theme preset to the presentation",
4768
1698
  inputSchema: ApplyThemePresetSchema.shape
4769
1699
  },
4770
1700
  async (params) => {
4771
- const result = await runMcpTool(
1701
+ const result = await runMcpTool2(
4772
1702
  params.filePath,
4773
1703
  (ctx) => applyThemePreset(ctx, params)
4774
1704
  );
4775
1705
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4776
1706
  }
4777
1707
  );
4778
- server2.registerTool(
1708
+ server.registerTool(
4779
1709
  "update_theme_colors",
4780
1710
  {
4781
1711
  description: "Update individual theme colors (accent1-6, dk1/2, lt1/2, hlink, folHlink)",
4782
1712
  inputSchema: UpdateThemeColorsSchema.shape
4783
1713
  },
4784
1714
  async (params) => {
4785
- const result = await runMcpTool(
1715
+ const result = await runMcpTool2(
4786
1716
  params.filePath,
4787
1717
  (ctx) => updateThemeColors(ctx, params)
4788
1718
  );
4789
1719
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4790
1720
  }
4791
1721
  );
4792
- server2.registerTool(
1722
+ server.registerTool(
4793
1723
  "update_theme_fonts",
4794
1724
  {
4795
1725
  description: "Update theme heading (major) and body (minor) fonts",
4796
1726
  inputSchema: UpdateThemeFontsSchema.shape
4797
1727
  },
4798
1728
  async (params) => {
4799
- const result = await runMcpTool(
1729
+ const result = await runMcpTool2(
4800
1730
  params.filePath,
4801
1731
  (ctx) => updateThemeFonts(ctx, params)
4802
1732
  );
4803
1733
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4804
1734
  }
4805
1735
  );
4806
- server2.registerTool(
1736
+ server.registerTool(
4807
1737
  "update_chart",
4808
1738
  {
4809
1739
  description: "Update chart type, title, legend, data labels, axis, or categories",
4810
1740
  inputSchema: UpdateChartSchema.shape
4811
1741
  },
4812
1742
  async (params) => {
4813
- const result = await runMcpTool(
1743
+ const result = await runMcpTool2(
4814
1744
  params.filePath,
4815
1745
  (ctx) => updateChart(ctx, params)
4816
1746
  );
4817
1747
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4818
1748
  }
4819
1749
  );
4820
- server2.registerTool(
1750
+ server.registerTool(
4821
1751
  "add_chart_series",
4822
1752
  {
4823
1753
  description: "Add a data series to an existing chart",
4824
1754
  inputSchema: AddChartSeriesSchema.shape
4825
1755
  },
4826
1756
  async (params) => {
4827
- const result = await runMcpTool(
1757
+ const result = await runMcpTool2(
4828
1758
  params.filePath,
4829
1759
  (ctx) => addChartSeriesT(ctx, params)
4830
1760
  );
4831
1761
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4832
1762
  }
4833
1763
  );
4834
- server2.registerTool(
1764
+ server.registerTool(
4835
1765
  "remove_chart_series",
4836
1766
  {
4837
1767
  description: "Remove a data series from a chart by index",
4838
1768
  inputSchema: RemoveChartSeriesSchema.shape
4839
1769
  },
4840
1770
  async (params) => {
4841
- const result = await runMcpTool(
1771
+ const result = await runMcpTool2(
4842
1772
  params.filePath,
4843
1773
  (ctx) => removeChartSeriesT(ctx, params)
4844
1774
  );
4845
1775
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4846
1776
  }
4847
1777
  );
4848
- server2.registerTool(
1778
+ server.registerTool(
4849
1779
  "update_chart_series_data",
4850
1780
  {
4851
1781
  description: "Update data values for a chart series",
4852
1782
  inputSchema: UpdateChartSeriesDataSchema.shape
4853
1783
  },
4854
1784
  async (params) => {
4855
- const result = await runMcpTool(
1785
+ const result = await runMcpTool2(
4856
1786
  params.filePath,
4857
1787
  (ctx) => updateChartSeriesData(ctx, params)
4858
1788
  );
4859
1789
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4860
1790
  }
4861
1791
  );
4862
- server2.registerTool(
1792
+ server.registerTool(
4863
1793
  "create_chart",
4864
1794
  {
4865
1795
  description: "Create a new chart element on a slide",
4866
1796
  inputSchema: CreateChartSchema.shape
4867
1797
  },
4868
1798
  async (params) => {
4869
- const result = await runMcpTool(
1799
+ const result = await runMcpTool2(
4870
1800
  params.filePath,
4871
1801
  (ctx) => createChart(ctx, params)
4872
1802
  );
4873
1803
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4874
1804
  }
4875
1805
  );
4876
- server2.registerTool(
1806
+ server.registerTool(
4877
1807
  "format_chart_data_point",
4878
1808
  {
4879
1809
  description: "Set per-data-point chart formatting: fill/stroke colour, stroke width, dash style (c:dPt/c:spPr), explosion, and marker override",
4880
1810
  inputSchema: FormatChartDataPointSchema.shape
4881
1811
  },
4882
1812
  async (params) => {
4883
- const result = await runMcpTool(
1813
+ const result = await runMcpTool2(
4884
1814
  params.filePath,
4885
1815
  (ctx) => formatChartDataPoint(ctx, params)
4886
1816
  );
4887
1817
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4888
1818
  }
4889
1819
  );
4890
- server2.registerTool(
1820
+ server.registerTool(
4891
1821
  "format_chart_data_label",
4892
1822
  {
4893
1823
  description: "Set a per-data-point data-label override (c:dLbl): show flags, position, custom text, and the label's own fill/line formatting (c:spPr) and font (c:txPr)",
4894
1824
  inputSchema: FormatChartDataLabelSchema.shape
4895
1825
  },
4896
1826
  async (params) => {
4897
- const result = await runMcpTool(
1827
+ const result = await runMcpTool2(
4898
1828
  params.filePath,
4899
1829
  (ctx) => formatChartDataLabel(ctx, params)
4900
1830
  );
4901
1831
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4902
1832
  }
4903
1833
  );
4904
- server2.registerTool(
1834
+ server.registerTool(
4905
1835
  "format_chart_series",
4906
1836
  {
4907
1837
  description: "Set a chart series marker (c:marker), trendline (c:trendline, incl. line width/dash), or error bars (c:errBars, incl. line width/dash)",
4908
1838
  inputSchema: FormatChartSeriesSchema.shape
4909
1839
  },
4910
1840
  async (params) => {
4911
- const result = await runMcpTool(
1841
+ const result = await runMcpTool2(
4912
1842
  params.filePath,
4913
1843
  (ctx) => formatChartSeries(ctx, params)
4914
1844
  );
4915
1845
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4916
1846
  }
4917
1847
  );
4918
- server2.registerTool(
1848
+ server.registerTool(
4919
1849
  "set_chart_helper_line",
4920
1850
  {
4921
1851
  description: "Set or remove a chart-level helper line on a line/stock/combo chart: c:dropLines or c:hiLowLines",
4922
1852
  inputSchema: SetChartHelperLineSchema.shape
4923
1853
  },
4924
1854
  async (params) => {
4925
- const result = await runMcpTool(
1855
+ const result = await runMcpTool2(
4926
1856
  params.filePath,
4927
1857
  (ctx) => setChartHelperLineT(ctx, params)
4928
1858
  );
4929
1859
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4930
1860
  }
4931
1861
  );
4932
- server2.registerTool(
1862
+ server.registerTool(
4933
1863
  "set_chart_color_map_override",
4934
1864
  {
4935
1865
  description: "Set or remove a chart's theme colour-map override (c:clrMapOvr), remapping theme colour roles for this chart only",
4936
1866
  inputSchema: SetChartColorMapOverrideSchema.shape
4937
1867
  },
4938
1868
  async (params) => {
4939
- const result = await runMcpTool(
1869
+ const result = await runMcpTool2(
4940
1870
  params.filePath,
4941
1871
  (ctx) => setChartColorMapOverrideT(ctx, params)
4942
1872
  );
4943
1873
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4944
1874
  }
4945
1875
  );
4946
- server2.registerTool(
1876
+ server.registerTool(
4947
1877
  "chart_user_shape_list",
4948
1878
  {
4949
1879
  description: "List a chart's drawing-overlay shapes (c:userShapes)",
4950
1880
  inputSchema: ListChartUserShapesSchema.shape
4951
1881
  },
4952
1882
  async (params) => {
4953
- const result = await runMcpTool(
1883
+ const result = await runMcpTool2(
4954
1884
  params.filePath,
4955
1885
  (ctx) => listChartUserShapesT(ctx, params)
4956
1886
  );
4957
1887
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4958
1888
  }
4959
1889
  );
4960
- server2.registerTool(
1890
+ server.registerTool(
4961
1891
  "chart_user_shape_add",
4962
1892
  {
4963
1893
  description: "Add a drawing-overlay shape (text box or connector) to a chart's c:userShapes",
4964
1894
  inputSchema: AddChartUserShapeSchema.shape
4965
1895
  },
4966
1896
  async (params) => {
4967
- const result = await runMcpTool(
1897
+ const result = await runMcpTool2(
4968
1898
  params.filePath,
4969
1899
  (ctx) => addChartUserShapeT(ctx, params)
4970
1900
  );
4971
1901
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4972
1902
  }
4973
1903
  );
4974
- server2.registerTool(
1904
+ server.registerTool(
4975
1905
  "chart_user_shape_update",
4976
1906
  {
4977
1907
  description: "Move, resize, or restyle one of a chart's drawing-overlay shapes by index",
4978
1908
  inputSchema: UpdateChartUserShapeSchema.shape
4979
1909
  },
4980
1910
  async (params) => {
4981
- const result = await runMcpTool(
1911
+ const result = await runMcpTool2(
4982
1912
  params.filePath,
4983
1913
  (ctx) => updateChartUserShapeT(ctx, params)
4984
1914
  );
4985
1915
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4986
1916
  }
4987
1917
  );
4988
- server2.registerTool(
1918
+ server.registerTool(
4989
1919
  "chart_user_shape_remove",
4990
1920
  {
4991
1921
  description: "Remove one of a chart's drawing-overlay shapes by index",
4992
1922
  inputSchema: RemoveChartUserShapeSchema.shape
4993
1923
  },
4994
1924
  async (params) => {
4995
- const result = await runMcpTool(
1925
+ const result = await runMcpTool2(
4996
1926
  params.filePath,
4997
1927
  (ctx) => removeChartUserShapeT(ctx, params)
4998
1928
  );
4999
1929
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5000
1930
  }
5001
1931
  );
5002
- server2.registerTool(
1932
+ server.registerTool(
5003
1933
  "manage_smart_art",
5004
1934
  {
5005
1935
  description: "Manage SmartArt: get nodes, add/remove/reorder/promote/demote nodes, or decompose to shapes",
5006
1936
  inputSchema: ManageSmartArtSchema.shape
5007
1937
  },
5008
1938
  async (params) => {
5009
- const result = await runMcpTool(
1939
+ const result = await runMcpTool2(
5010
1940
  params.filePath,
5011
1941
  (ctx) => manageSmartArt(ctx, params)
5012
1942
  );
5013
1943
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5014
1944
  }
5015
1945
  );
5016
- server2.registerTool(
1946
+ server.registerTool(
5017
1947
  "find_placeholders",
5018
1948
  {
5019
1949
  description: "Discover all {{placeholder}} tokens in the presentation",
5020
1950
  inputSchema: FindPlaceholdersSchema.shape
5021
1951
  },
5022
1952
  async (params) => {
5023
- const result = await runMcpTool(
1953
+ const result = await runMcpTool2(
5024
1954
  params.filePath,
5025
1955
  (ctx) => findPlaceholdersT(ctx)
5026
1956
  );
5027
1957
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5028
1958
  }
5029
1959
  );
5030
- server2.registerTool(
1960
+ server.registerTool(
5031
1961
  "apply_template",
5032
1962
  {
5033
1963
  description: "Replace {{placeholder}} tokens with provided values (mail merge)",
5034
1964
  inputSchema: ApplyTemplateSchema.shape
5035
1965
  },
5036
1966
  async (params) => {
5037
- const result = await runMcpTool(
1967
+ const result = await runMcpTool2(
5038
1968
  params.filePath,
5039
1969
  (ctx) => applyTemplateT(ctx, { data: params.data })
5040
1970
  );
5041
1971
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5042
1972
  }
5043
1973
  );
5044
- server2.registerTool(
1974
+ server.registerTool(
5045
1975
  "get_metadata",
5046
1976
  {
5047
1977
  description: "Get presentation metadata (title, author, keywords, custom properties)",
5048
1978
  inputSchema: GetMetadataSchema.shape
5049
1979
  },
5050
1980
  async (params) => {
5051
- const result = await runMcpTool(params.filePath, (ctx) => getMetadata(ctx));
1981
+ const result = await runMcpTool2(params.filePath, (ctx) => getMetadata(ctx));
5052
1982
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5053
1983
  }
5054
1984
  );
5055
- server2.registerTool(
1985
+ server.registerTool(
5056
1986
  "update_metadata",
5057
1987
  {
5058
1988
  description: "Update presentation metadata (title, author, company, custom properties)",
5059
1989
  inputSchema: UpdateMetadataSchema.shape
5060
1990
  },
5061
1991
  async (params) => {
5062
- const result = await runMcpTool(
1992
+ const result = await runMcpTool2(
5063
1993
  params.filePath,
5064
1994
  (ctx) => updateMetadata(ctx, params)
5065
1995
  );
5066
1996
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5067
1997
  }
5068
1998
  );
5069
- server2.registerTool(
1999
+ server.registerTool(
5070
2000
  "manage_sections",
5071
2001
  {
5072
2002
  description: "List, add, remove, reorder sections or move slides between sections",
5073
2003
  inputSchema: ManageSectionsSchema.shape
5074
2004
  },
5075
2005
  async (params) => {
5076
- const result = await runMcpTool(
2006
+ const result = await runMcpTool2(
5077
2007
  params.filePath,
5078
2008
  (ctx) => manageSections(ctx, params)
5079
2009
  );
5080
2010
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5081
2011
  }
5082
2012
  );
5083
- server2.registerTool(
2013
+ server.registerTool(
5084
2014
  "export_to_svg",
5085
2015
  {
5086
2016
  description: "Export all or specific slides to SVG strings",
5087
2017
  inputSchema: ExportToSvgSchema.shape
5088
2018
  },
5089
2019
  async (params) => {
5090
- const result = await runMcpTool(
2020
+ const result = await runMcpTool2(
5091
2021
  params.filePath,
5092
2022
  (ctx) => exportToSvg(ctx, params)
5093
2023
  );
5094
2024
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5095
2025
  }
5096
2026
  );
5097
- server2.registerTool(
2027
+ server.registerTool(
5098
2028
  "export_slide_svg",
5099
2029
  {
5100
2030
  description: "Export a single slide to SVG",
5101
2031
  inputSchema: ExportSlideSvgSchema.shape
5102
2032
  },
5103
2033
  async (params) => {
5104
- const result = await runMcpTool(
2034
+ const result = await runMcpTool2(
5105
2035
  params.filePath,
5106
2036
  (ctx) => exportSlideSvg(ctx, params)
5107
2037
  );
5108
2038
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5109
2039
  }
5110
2040
  );
5111
- server2.registerTool(
2041
+ server.registerTool(
5112
2042
  "export_to_json",
5113
2043
  {
5114
2044
  description: "Export the presentation to the portable pptx-viewer-json document format (self-contained, binary assets embedded as base64)",
5115
2045
  inputSchema: ExportToJsonSchema.shape
5116
2046
  },
5117
2047
  async (params) => {
5118
- const result = await runMcpTool(
2048
+ const result = await runMcpTool2(
5119
2049
  params.filePath,
5120
2050
  (ctx) => exportToJson(ctx, params)
5121
2051
  );
5122
2052
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5123
2053
  }
5124
2054
  );
5125
- server2.registerTool(
2055
+ server.registerTool(
5126
2056
  "import_from_json",
5127
2057
  {
5128
2058
  description: "Replace the presentation content with a deck imported from a pptx-viewer-json document",
5129
2059
  inputSchema: ImportFromJsonSchema.shape
5130
2060
  },
5131
2061
  async (params) => {
5132
- const result = await runMcpTool(
2062
+ const result = await runMcpTool2(
5133
2063
  params.filePath,
5134
2064
  (ctx) => importFromJson(ctx, params)
5135
2065
  );
5136
2066
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5137
2067
  }
5138
2068
  );
5139
- server2.registerTool(
2069
+ server.registerTool(
5140
2070
  "manage_hyperlinks",
5141
2071
  {
5142
2072
  description: "List, set, or remove hyperlinks/actions on elements",
5143
2073
  inputSchema: ManageHyperlinksSchema.shape
5144
2074
  },
5145
2075
  async (params) => {
5146
- const result = await runMcpTool(
2076
+ const result = await runMcpTool2(
5147
2077
  params.filePath,
5148
2078
  (ctx) => manageHyperlinks(ctx, params)
5149
2079
  );
5150
2080
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5151
2081
  }
5152
2082
  );
5153
- server2.registerTool(
2083
+ server.registerTool(
5154
2084
  "replace_geometry",
5155
2085
  {
5156
2086
  description: "Replace a shape element geometry with a preset or custom SVG path",
5157
2087
  inputSchema: ReplaceGeometrySchema.shape
5158
2088
  },
5159
2089
  async (params) => {
5160
- const result = await runMcpTool(
2090
+ const result = await runMcpTool2(
5161
2091
  params.filePath,
5162
2092
  (ctx) => replaceGeometry(ctx, {
5163
2093
  ...params,
@@ -5167,21 +2097,21 @@ function createServer() {
5167
2097
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5168
2098
  }
5169
2099
  );
5170
- server2.registerTool(
2100
+ server.registerTool(
5171
2101
  "set_element_lock",
5172
2102
  {
5173
2103
  description: "Lock or unlock an element (prevent move, resize, rotation, selection, text edit)",
5174
2104
  inputSchema: SetElementLockSchema.shape
5175
2105
  },
5176
2106
  async (params) => {
5177
- const result = await runMcpTool(
2107
+ const result = await runMcpTool2(
5178
2108
  params.filePath,
5179
2109
  (ctx) => setElementLockT(ctx, params)
5180
2110
  );
5181
2111
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5182
2112
  }
5183
2113
  );
5184
- server2.registerTool(
2114
+ server.registerTool(
5185
2115
  "validate_presentation",
5186
2116
  {
5187
2117
  description: "Validate PPTX structural integrity (content types, relationships, XML)",
@@ -5189,13 +2119,13 @@ function createServer() {
5189
2119
  },
5190
2120
  async (params) => {
5191
2121
  const { readFile: readFile2 } = await import('fs/promises');
5192
- const safePath = resolveScopedFilePath(params.filePath);
2122
+ const safePath = resolveScopedFilePath2(params.filePath);
5193
2123
  const bytes = await readFile2(safePath);
5194
2124
  const result = await validatePresentation(bytes.buffer);
5195
2125
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5196
2126
  }
5197
2127
  );
5198
- server2.registerTool(
2128
+ server.registerTool(
5199
2129
  "repair_presentation",
5200
2130
  {
5201
2131
  description: "Auto-repair common PPTX structural issues",
@@ -5203,7 +2133,7 @@ function createServer() {
5203
2133
  },
5204
2134
  async (params) => {
5205
2135
  const { readFile: readFile2, writeFile: writeFile2 } = await import('fs/promises');
5206
- const safePath = resolveScopedFilePath(params.filePath);
2136
+ const safePath = resolveScopedFilePath2(params.filePath);
5207
2137
  const bytes = await readFile2(safePath);
5208
2138
  const { result, repairedBytes } = await repairPresentation(
5209
2139
  bytes.buffer
@@ -5214,147 +2144,144 @@ function createServer() {
5214
2144
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5215
2145
  }
5216
2146
  );
5217
- server2.registerTool(
2147
+ server.registerTool(
5218
2148
  "get_presentation_properties",
5219
2149
  {
5220
2150
  description: "Get slideshow properties (show type, loop, advance mode, slide range)",
5221
2151
  inputSchema: GetPresentationPropertiesSchema.shape
5222
2152
  },
5223
2153
  async (params) => {
5224
- const result = await runMcpTool(
2154
+ const result = await runMcpTool2(
5225
2155
  params.filePath,
5226
2156
  (ctx) => getPresentationProperties(ctx)
5227
2157
  );
5228
2158
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5229
2159
  }
5230
2160
  );
5231
- server2.registerTool(
2161
+ server.registerTool(
5232
2162
  "update_presentation_properties",
5233
2163
  {
5234
2164
  description: "Update slideshow properties (show type, loop, advance mode, pen color)",
5235
2165
  inputSchema: UpdatePresentationPropertiesSchema.shape
5236
2166
  },
5237
2167
  async (params) => {
5238
- const result = await runMcpTool(
2168
+ const result = await runMcpTool2(
5239
2169
  params.filePath,
5240
2170
  (ctx) => updatePresentationProperties(ctx, params)
5241
2171
  );
5242
2172
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5243
2173
  }
5244
2174
  );
5245
- server2.registerTool(
2175
+ server.registerTool(
5246
2176
  "get_layouts",
5247
2177
  {
5248
2178
  description: "List available slide layouts from the presentation masters",
5249
2179
  inputSchema: GetLayoutsSchema.shape
5250
2180
  },
5251
2181
  async (params) => {
5252
- const result = await runMcpTool(params.filePath, (ctx) => getLayouts(ctx));
2182
+ const result = await runMcpTool2(params.filePath, (ctx) => getLayouts(ctx));
5253
2183
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5254
2184
  }
5255
2185
  );
5256
- server2.registerTool(
2186
+ server.registerTool(
5257
2187
  "apply_layout",
5258
2188
  {
5259
2189
  description: "Apply a slide layout to a specific slide",
5260
2190
  inputSchema: ApplyLayoutSchema.shape
5261
2191
  },
5262
2192
  async (params) => {
5263
- const result = await runMcpTool(
2193
+ const result = await runMcpTool2(
5264
2194
  params.filePath,
5265
2195
  (ctx) => applyLayout(ctx, params)
5266
2196
  );
5267
2197
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5268
2198
  }
5269
2199
  );
5270
- server2.registerTool(
2200
+ server.registerTool(
5271
2201
  "ole_get_content",
5272
2202
  {
5273
2203
  description: "Inspect an embedded OLE object's editable content: resolved kind, plus the sheet grid, paragraph list, or nested-deck slide summaries, whichever applies",
5274
2204
  inputSchema: GetOleContentSchema.shape
5275
2205
  },
5276
2206
  async (params) => {
5277
- const result = await runMcpTool(
2207
+ const result = await runMcpTool2(
5278
2208
  params.filePath,
5279
2209
  (ctx) => getOleContent(ctx, params)
5280
2210
  );
5281
2211
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5282
2212
  }
5283
2213
  );
5284
- server2.registerTool(
2214
+ server.registerTool(
5285
2215
  "ole_set_sheet_cell",
5286
2216
  {
5287
2217
  description: "Edit one cell of an embedded Excel OLE object's first worksheet",
5288
2218
  inputSchema: SetOleSheetCellSchema.shape
5289
2219
  },
5290
2220
  async (params) => {
5291
- const result = await runMcpTool(
2221
+ const result = await runMcpTool2(
5292
2222
  params.filePath,
5293
2223
  (ctx) => setOleSheetCell(ctx, params)
5294
2224
  );
5295
2225
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5296
2226
  }
5297
2227
  );
5298
- server2.registerTool(
2228
+ server.registerTool(
5299
2229
  "ole_set_document_paragraph",
5300
2230
  {
5301
2231
  description: "Replace one paragraph's text in an embedded Word (.docx or legacy .doc) OLE object",
5302
2232
  inputSchema: SetOleDocumentParagraphSchema.shape
5303
2233
  },
5304
2234
  async (params) => {
5305
- const result = await runMcpTool(
2235
+ const result = await runMcpTool2(
5306
2236
  params.filePath,
5307
2237
  (ctx) => setOleDocumentParagraph(ctx, params)
5308
2238
  );
5309
2239
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5310
2240
  }
5311
2241
  );
5312
- server2.registerTool(
2242
+ server.registerTool(
5313
2243
  "ole_set_deck_slide_title",
5314
2244
  {
5315
2245
  description: "Edit one text-bearing shape on one slide of an embedded nested-deck (PowerPoint) OLE object, via a full load/save round-trip through the nested deck (call ole_get_content first to discover each slide's elementIds)",
5316
2246
  inputSchema: SetOleDeckSlideTitleSchema.shape
5317
2247
  },
5318
2248
  async (params) => {
5319
- const result = await runMcpTool(
2249
+ const result = await runMcpTool2(
5320
2250
  params.filePath,
5321
2251
  (ctx) => setOleDeckSlideTitle(ctx, params)
5322
2252
  );
5323
2253
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5324
2254
  }
5325
2255
  );
5326
- server2.registerTool(
2256
+ server.registerTool(
5327
2257
  "ole_replace_file",
5328
2258
  {
5329
2259
  description: `Replace an embedded OLE object's payload wholesale with an arbitrary file; works for any OLE kind, including a generic "Package" object or an unsupported format`,
5330
2260
  inputSchema: ReplaceOleFileSchema.shape
5331
2261
  },
5332
2262
  async (params) => {
5333
- const result = await runMcpTool(
2263
+ const result = await runMcpTool2(
5334
2264
  params.filePath,
5335
2265
  (ctx) => replaceOleFileT(ctx, params)
5336
2266
  );
5337
2267
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5338
2268
  }
5339
2269
  );
5340
- server2.registerTool(
2270
+ server.registerTool(
5341
2271
  "ole_set_object_name",
5342
2272
  {
5343
2273
  description: "Rename an OLE object's Object Name (p:oleObj/@name); regenerates the baked-in icon caption too when the object is displayed as an icon",
5344
2274
  inputSchema: SetOleObjectNameSchema.shape
5345
2275
  },
5346
2276
  async (params) => {
5347
- const result = await runMcpTool(
2277
+ const result = await runMcpTool2(
5348
2278
  params.filePath,
5349
2279
  (ctx) => setOleObjectNameT(ctx, params)
5350
2280
  );
5351
2281
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
5352
2282
  }
5353
2283
  );
5354
- return server2;
5355
2284
  }
5356
2285
 
5357
- // src/mcp/index.ts
5358
- var server = createServer();
5359
- var transport = new stdio_js.StdioServerTransport();
5360
- void server.connect(transport);
2286
+ exports.createServer = createServer;
2287
+ exports.registerTools = registerTools;