@superdoc/mcp 1.8.0-next.4 → 1.8.0-next.5

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.
Files changed (2) hide show
  1. package/dist/index.js +156 -23
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31614,7 +31614,7 @@ var init_host = __esm(() => {
31614
31614
  });
31615
31615
 
31616
31616
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31617
- var SDK_VERSION = "2.21.0-next.4";
31617
+ var SDK_VERSION = "2.21.0-next.5";
31618
31618
 
31619
31619
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31620
31620
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -134064,11 +134064,16 @@ function createParagraphSpanCollector(options) {
134064
134064
  const bookmarkStarts = [];
134065
134065
  const bookmarkEnds = [];
134066
134066
  const openParagraphs = [];
134067
+ const wmlBodyPath = [];
134067
134068
  let storyRoot = null;
134068
134069
  const walkOptions = {
134069
134070
  fragment: options.fragment,
134070
134071
  additionalNamespaces: options.additionalNamespaces,
134071
134072
  onOpenTag(event) {
134073
+ const directBodyChild = wmlBodyPath.at(-1) === true;
134074
+ if (!event.tag.isSelfClosing) {
134075
+ wmlBodyPath.push(event.tag.namespaceUri === NS_W && event.tag.localName === "body");
134076
+ }
134072
134077
  if (!storyRoot && event.tag.namespaceUri === NS_W && STORY_ROOT_LOCAL_NAMES.has(event.tag.localName)) {
134073
134078
  storyRoot = rootFromEvent(event);
134074
134079
  }
@@ -134089,10 +134094,11 @@ function createParagraphSpanCollector(options) {
134089
134094
  openParagraphs.push(paragraphs.length - 1);
134090
134095
  return;
134091
134096
  }
134092
- if (openParagraphs.length > 0 && event.tag.namespaceUri === NS_W && (event.tag.localName === "bookmarkStart" || event.tag.localName === "bookmarkEnd")) {
134097
+ if ((openParagraphs.length > 0 || directBodyChild) && event.tag.namespaceUri === NS_W && (event.tag.localName === "bookmarkStart" || event.tag.localName === "bookmarkEnd")) {
134093
134098
  const markers = event.tag.localName === "bookmarkStart" ? bookmarkStarts : bookmarkEnds;
134094
134099
  markers.push({
134095
- paragraphNamespaceBindings: paragraphs[openParagraphs.at(-1)].namespaceBindings,
134100
+ paragraphNamespaceBindings: openParagraphs.length > 0 ? paragraphs[openParagraphs.at(-1)].namespaceBindings : event.namespaceBindings,
134101
+ ...openParagraphs.length === 0 && directBodyChild ? { directBodyChild: true } : {},
134096
134102
  openStart: event.start,
134097
134103
  openEnd: event.end,
134098
134104
  namespaceBindings: event.namespaceBindings
@@ -134100,6 +134106,8 @@ function createParagraphSpanCollector(options) {
134100
134106
  }
134101
134107
  },
134102
134108
  onCloseTag(event) {
134109
+ if (!event.tag.isSelfClosing)
134110
+ wmlBodyPath.pop();
134103
134111
  if (event.tag.isSelfClosing || !isWmlParagraph(event))
134104
134112
  return;
134105
134113
  const index = openParagraphs.pop();
@@ -146808,6 +146816,7 @@ function bindParagraphIndexScanFacts(sourceBytes, facts) {
146808
146816
  previousEnd = byteEnd;
146809
146817
  }
146810
146818
  const bindMarkers = (markers) => markers.map((marker) => ({
146819
+ ...marker.directBodyChild ? { directBodyChild: true } : {},
146811
146820
  markerByteStart: byteByCharOffset.get(marker.openStart),
146812
146821
  markerXml: facts.sourceXml.slice(marker.openStart, marker.openEnd),
146813
146822
  namespaceBindings: marker.namespaceBindings,
@@ -146915,6 +146924,7 @@ function scanParagraphParaIdNormalizationInput(xml, fragmentNamespaces, captureP
146915
146924
  if (captureParagraphIndexFacts && !event.tag.isSelfClosing) {
146916
146925
  elementFrames.push({
146917
146926
  bodyRoot,
146927
+ wmlBodyRoot: event.tag.namespaceUri === NS_W && event.tag.localName === "body",
146918
146928
  ...bodyChildOrdinal == null ? {} : { bodyChildOrdinal },
146919
146929
  ...blockSdtRangeIndex == null ? {} : { blockSdtRangeIndex }
146920
146930
  });
@@ -146925,10 +146935,11 @@ function scanParagraphParaIdNormalizationInput(xml, fragmentNamespaces, captureP
146925
146935
  if (storyRoot == null && event.tag.namespaceUri === NS_W && STORY_ROOT_LOCAL_NAMES2.has(event.tag.localName)) {
146926
146936
  storyRoot = storyRootFromEvent(event);
146927
146937
  }
146928
- if (captureParagraphIndexFacts && openParagraphs.length > 0 && event.tag.namespaceUri === NS_W && (event.tag.localName === "bookmarkStart" || event.tag.localName === "bookmarkEnd")) {
146938
+ if (captureParagraphIndexFacts && (openParagraphs.length > 0 || parent?.wmlBodyRoot === true) && event.tag.namespaceUri === NS_W && (event.tag.localName === "bookmarkStart" || event.tag.localName === "bookmarkEnd")) {
146929
146939
  const markers = event.tag.localName === "bookmarkStart" ? bookmarkStarts : bookmarkEnds;
146930
146940
  markers.push({
146931
- paragraphNamespaceBindings: paragraphs[openParagraphs.at(-1)].namespaceBindings,
146941
+ paragraphNamespaceBindings: openParagraphs.length > 0 ? paragraphs[openParagraphs.at(-1)].namespaceBindings : event.namespaceBindings,
146942
+ ...openParagraphs.length === 0 && parent?.wmlBodyRoot === true ? { directBodyChild: true } : {},
146932
146943
  openStart: event.start,
146933
146944
  openEnd: event.end,
146934
146945
  namespaceBindings: event.namespaceBindings
@@ -253350,8 +253361,12 @@ function buildBookmarkCatalogSynchronously(input, includeParagraphFingerprint) {
253350
253361
  markerByteStart: utf8Offsets.byteOffsetAt(tag.openStart),
253351
253362
  markerXml: xml.slice(tag.openStart, tag.openEnd),
253352
253363
  namespaceBindings: tag.namespaceBindings,
253353
- paragraphNamespaceBindings: tag.paragraphNamespaceBindings
253364
+ paragraphNamespaceBindings: tag.paragraphNamespaceBindings,
253365
+ ...tag.directBodyChild ? { directBodyChild: true } : {}
253354
253366
  }));
253367
+ const bookmarkEnds = bookmarkEndsFromInput(input, paragraphScan, xml);
253368
+ const pairing = createBookmarkPairing();
253369
+ for (const _ of pairBookmarkOccurrences(bookmarkStarts, bookmarkEnds, pairing)) {}
253355
253370
  for (const tag of bookmarkStarts) {
253356
253371
  bookmarkStartTagsRead += 1;
253357
253372
  const projected = projectBookmarkStart({
@@ -253360,16 +253375,24 @@ function buildBookmarkCatalogSynchronously(input, includeParagraphFingerprint) {
253360
253375
  storyId: input.storyId,
253361
253376
  partUri: input.partUri,
253362
253377
  paragraphLocators: paragraphFacts.locators,
253363
- markerByteStart: tag.markerByteStart
253378
+ markerByteStart: tag.markerByteStart,
253379
+ directBodyChild: tag.directBodyChild === true,
253380
+ followingBodyParagraph: followingBodyParagraph(input.bytes, tag, pairing, paragraphFacts.locators)
253364
253381
  });
253365
- if (!projected || seenBookmarkIds.has(projected.bookmarkId))
253382
+ if (!projected)
253383
+ continue;
253384
+ if (pairing.overlappingStartBytes.has(projected.markerByteStart)) {
253385
+ seenBookmarkIds.add(projected.bookmarkId);
253386
+ continue;
253387
+ }
253388
+ if (pairing.invalidIds.has(projected.bookmarkId) && seenBookmarkIds.has(projected.bookmarkId))
253366
253389
  continue;
253367
253390
  seenBookmarkIds.add(projected.bookmarkId);
253368
253391
  bookmarks.push(projected);
253369
253392
  if (!byName.has(projected.name))
253370
253393
  byName.set(projected.name, projected);
253371
253394
  }
253372
- for (const _ of projectBookmarkRanges(input.bytes, bookmarks, bookmarkStarts, bookmarkEndsFromInput(input, paragraphScan, xml), paragraphFacts.locators)) {}
253395
+ for (const _ of projectBookmarkRanges(input.bytes, bookmarks, bookmarkStarts, pairing, paragraphFacts.locators)) {}
253373
253396
  if (!paragraphSource.isCurrent()) {
253374
253397
  throw new Error("bookmark catalog paragraph index changed during build");
253375
253398
  }
@@ -253405,8 +253428,20 @@ async function buildBookmarkCatalogCooperativelyInternal(input) {
253405
253428
  markerByteStart: utf8Offsets.byteOffsetAt(tag.openStart),
253406
253429
  markerXml: xml.slice(tag.openStart, tag.openEnd),
253407
253430
  namespaceBindings: tag.namespaceBindings,
253408
- paragraphNamespaceBindings: tag.paragraphNamespaceBindings
253431
+ paragraphNamespaceBindings: tag.paragraphNamespaceBindings,
253432
+ ...tag.directBodyChild ? { directBodyChild: true } : {}
253409
253433
  }));
253434
+ const bookmarkEnds = bookmarkEndsFromInput(input, paragraphScan, xml);
253435
+ const pairing = createBookmarkPairing();
253436
+ let markersRead = 0;
253437
+ for (const _ of pairBookmarkOccurrences(bookmarkStarts, bookmarkEnds, pairing)) {
253438
+ markersRead += 1;
253439
+ if (markersRead % BOOKMARK_CHECKPOINT_SIZE === 0) {
253440
+ await input.yieldPoint();
253441
+ if (!paragraphSource.isCurrent() || !input.isCurrent())
253442
+ return null;
253443
+ }
253444
+ }
253410
253445
  for (let index = 0;index < bookmarkStarts.length; index += 1) {
253411
253446
  const tag = bookmarkStarts[index];
253412
253447
  bookmarkStartTagsRead += 1;
@@ -253416,9 +253451,13 @@ async function buildBookmarkCatalogCooperativelyInternal(input) {
253416
253451
  storyId: input.storyId,
253417
253452
  partUri: input.partUri,
253418
253453
  paragraphLocators: paragraphFacts,
253419
- markerByteStart: tag.markerByteStart
253454
+ markerByteStart: tag.markerByteStart,
253455
+ directBodyChild: tag.directBodyChild === true,
253456
+ followingBodyParagraph: followingBodyParagraph(input.bytes, tag, pairing, paragraphFacts)
253420
253457
  });
253421
- if (projected && !seenBookmarkIds.has(projected.bookmarkId)) {
253458
+ if (projected && pairing.overlappingStartBytes.has(projected.markerByteStart)) {
253459
+ seenBookmarkIds.add(projected.bookmarkId);
253460
+ } else if (projected && (!pairing.invalidIds.has(projected.bookmarkId) || !seenBookmarkIds.has(projected.bookmarkId))) {
253422
253461
  seenBookmarkIds.add(projected.bookmarkId);
253423
253462
  bookmarks.push(projected);
253424
253463
  if (!byName.has(projected.name))
@@ -253431,7 +253470,7 @@ async function buildBookmarkCatalogCooperativelyInternal(input) {
253431
253470
  }
253432
253471
  }
253433
253472
  let endpointsRead = 0;
253434
- for (const _ of projectBookmarkRanges(input.bytes, bookmarks, bookmarkStarts, bookmarkEndsFromInput(input, paragraphScan, xml), paragraphFacts)) {
253473
+ for (const _ of projectBookmarkRanges(input.bytes, bookmarks, bookmarkStarts, pairing, paragraphFacts)) {
253435
253474
  endpointsRead += 1;
253436
253475
  if (endpointsRead % ENDPOINT_CHECKPOINT_SIZE === 0) {
253437
253476
  await input.yieldPoint();
@@ -253465,11 +253504,81 @@ function bookmarkEndsFromInput(input, scan, xml) {
253465
253504
  markerByteStart: offsets.byteOffsetAt(tag.openStart),
253466
253505
  markerXml: xml.slice(tag.openStart, tag.openEnd),
253467
253506
  namespaceBindings: tag.namespaceBindings,
253468
- paragraphNamespaceBindings: tag.paragraphNamespaceBindings
253507
+ paragraphNamespaceBindings: tag.paragraphNamespaceBindings,
253508
+ ...tag.directBodyChild ? { directBodyChild: true } : {}
253469
253509
  }));
253470
253510
  }
253471
- function* projectBookmarkRanges(bytes, bookmarks, starts, ends, paragraphs) {
253472
- const byId = new Map(bookmarks.map((bookmark) => [bookmark.bookmarkId, bookmark]));
253511
+ function createBookmarkPairing() {
253512
+ return {
253513
+ endsByStartByte: new Map,
253514
+ invalidIds: new Set,
253515
+ invalidStartBytes: new Set,
253516
+ overlappingStartBytes: new Set
253517
+ };
253518
+ }
253519
+ function* pairBookmarkOccurrences(starts, ends, pairing) {
253520
+ const openById = new Map;
253521
+ let startIndex = 0;
253522
+ let endIndex = 0;
253523
+ while (startIndex < starts.length || endIndex < ends.length) {
253524
+ const start = starts[startIndex];
253525
+ const end = ends[endIndex];
253526
+ const isStart = start != null && (end == null || start.markerByteStart < end.markerByteStart);
253527
+ const marker = isStart ? start : end;
253528
+ const id = readWordAttribute3(marker.markerXml, "id", marker.namespaceBindings);
253529
+ if (isStart)
253530
+ startIndex += 1;
253531
+ else
253532
+ endIndex += 1;
253533
+ if (id != null) {
253534
+ const open2 = openById.get(id);
253535
+ if (isStart) {
253536
+ if (open2) {
253537
+ pairing.invalidIds.add(id);
253538
+ pairing.invalidStartBytes.add(open2.markerByteStart);
253539
+ pairing.overlappingStartBytes.add(open2.markerByteStart);
253540
+ pairing.overlappingStartBytes.add(marker.markerByteStart);
253541
+ } else
253542
+ openById.set(id, marker);
253543
+ } else if (open2) {
253544
+ pairing.endsByStartByte.set(open2.markerByteStart, marker);
253545
+ openById.delete(id);
253546
+ } else
253547
+ pairing.invalidIds.add(id);
253548
+ }
253549
+ yield;
253550
+ }
253551
+ for (const [id, start] of openById) {
253552
+ pairing.invalidIds.add(id);
253553
+ pairing.invalidStartBytes.add(start.markerByteStart);
253554
+ }
253555
+ }
253556
+ function followingBodyParagraph(bytes, start, pairing, paragraphs) {
253557
+ if (!start.directBodyChild || !/\/\s*>$/.test(start.markerXml))
253558
+ return null;
253559
+ const id = readWordAttribute3(start.markerXml, "id", start.namespaceBindings);
253560
+ const end = pairing.endsByStartByte.get(start.markerByteStart);
253561
+ if (id == null || pairing.invalidStartBytes.has(start.markerByteStart) || !end?.directBodyChild || !/\/\s*>$/.test(end.markerXml))
253562
+ return null;
253563
+ const startEnd = start.markerByteStart + TE40.encode(start.markerXml).length;
253564
+ if (!/^\s*$/.test(TD75.decode(bytes.subarray(startEnd, end.markerByteStart))))
253565
+ return null;
253566
+ const endEnd = end.markerByteStart + TE40.encode(end.markerXml).length;
253567
+ let low = 0;
253568
+ let high = paragraphs.length;
253569
+ while (low < high) {
253570
+ const mid = low + high >>> 1;
253571
+ if (paragraphs[mid].byteStart < endEnd)
253572
+ low = mid + 1;
253573
+ else
253574
+ high = mid;
253575
+ }
253576
+ const paragraph = paragraphs[low];
253577
+ if (!paragraph || !/^\s*$/.test(TD75.decode(bytes.subarray(endEnd, paragraph.byteStart))))
253578
+ return null;
253579
+ return paragraph;
253580
+ }
253581
+ function* projectBookmarkRanges(bytes, bookmarks, starts, pairing, paragraphs) {
253473
253582
  const startsByByte = new Map(starts.map((start) => [start.markerByteStart, start]));
253474
253583
  const offsetsByParagraph = new Map;
253475
253584
  const endpoint = (marker) => {
@@ -253485,10 +253594,9 @@ function* projectBookmarkRanges(bytes, bookmarks, starts, ends, paragraphs) {
253485
253594
  const offset = offsets.get(marker.markerByteStart);
253486
253595
  return offset == null ? null : { blockId: paragraph.blockId, offset };
253487
253596
  };
253488
- for (const end of ends) {
253489
- const id = readWordAttribute3(end.markerXml, "id", end.namespaceBindings);
253490
- const bookmark = id == null ? undefined : byId.get(id);
253491
- if (bookmark && !bookmark.range && end.markerByteStart >= bookmark.markerByteStart) {
253597
+ for (const bookmark of bookmarks) {
253598
+ const end = pairing.endsByStartByte.get(bookmark.markerByteStart);
253599
+ if (end && !bookmark.range && !pairing.invalidStartBytes.has(bookmark.markerByteStart)) {
253492
253600
  const start = startsByByte.get(bookmark.markerByteStart);
253493
253601
  const from = start ? endpoint(start) : null;
253494
253602
  const to = endpoint(end);
@@ -253549,7 +253657,7 @@ function projectBookmarkStart(input) {
253549
253657
  const name = readWordAttribute3(input.markerXml, "name", input.namespaceBindings);
253550
253658
  if (!bookmarkId || !name)
253551
253659
  return null;
253552
- const paragraph = findContainingParagraphLocator(input.paragraphLocators, input.markerByteStart);
253660
+ const paragraph = input.directBodyChild ? input.followingBodyParagraph : findContainingParagraphLocator(input.paragraphLocators, input.markerByteStart);
253553
253661
  if (!paragraph)
253554
253662
  return null;
253555
253663
  const colFirst = readWordAttribute3(input.markerXml, "colFirst", input.namespaceBindings);
@@ -253562,6 +253670,9 @@ function projectBookmarkStart(input) {
253562
253670
  partUri: input.partUri,
253563
253671
  blockId: paragraph.blockId,
253564
253672
  markerByteStart: input.markerByteStart,
253673
+ ...input.followingBodyParagraph ? {
253674
+ range: { from: { blockId: paragraph.blockId, offset: 0 }, to: { blockId: paragraph.blockId, offset: 0 } }
253675
+ } : {},
253565
253676
  ...tableColumn ? { tableColumn } : {}
253566
253677
  };
253567
253678
  }
@@ -297752,6 +297863,16 @@ function insertBookmarksIntoParagraphs(context, insertions, txIdPrefix) {
297752
297863
  return committed;
297753
297864
  return { ok: true, txId: committed.txId, bookmarkIds };
297754
297865
  }
297866
+ function ambiguousBookmarkIdFailure(context, entry) {
297867
+ const xml = readPartXml(context, entry.partUri);
297868
+ const scan = xml == null ? null : readBookmarkMarkerSpans(xml);
297869
+ if (!scan || scan.markers.filter((marker) => marker.kind === "start" && marker.bookmarkId === entry.bookmarkId).length <= 1)
297870
+ return null;
297871
+ return {
297872
+ code: "CAPABILITY_UNAVAILABLE",
297873
+ message: "Unable to mutate a bookmark whose imported ID identifies multiple occurrences."
297874
+ };
297875
+ }
297755
297876
  function renameBookmarkMarkup(context, entry, newName, txIdPrefix, options) {
297756
297877
  const xml = readPartXml(context, entry.partUri);
297757
297878
  const bytes = readPartBytes2(context, entry.partUri);
@@ -372721,15 +372842,21 @@ class V2BookmarksAdapter {
372721
372842
  return { attempts: maxRestarts + 1, restarts: maxRestarts, catalogPublished: false };
372722
372843
  }
372723
372844
  list(query3) {
372724
- const all2 = listBookmarkEntriesForQuery(this.context, query3?.in);
372845
+ const documentEntries = listBookmarkEntriesForQuery(this.context);
372846
+ const all2 = query3?.in ? listBookmarkEntriesForQuery(this.context, query3.in) : documentEntries;
372725
372847
  const offset = Math.max(0, Number.isFinite(query3?.offset) ? Number(query3?.offset) : 0);
372726
372848
  const requestedLimit = Number.isFinite(query3?.limit) ? Number(query3?.limit) : all2.length;
372727
372849
  const limit = Math.max(0, requestedLimit);
372728
372850
  const slice = all2.slice(offset, offset + limit);
372851
+ const idCounts = new Map;
372852
+ for (const entry of documentEntries) {
372853
+ idCounts.set(entry.bookmarkId, (idCounts.get(entry.bookmarkId) ?? 0) + 1);
372854
+ }
372729
372855
  const items = slice.map((entry) => {
372730
372856
  const info = projectBookmarkInfo(this.context, entry);
372731
372857
  const handle = buildResolvedHandle(`bookmark:${entry.name}`, "stable", "sdt");
372732
- return buildDiscoveryItem(entry.bookmarkId, handle, info);
372858
+ const discoveryId = idCounts.get(entry.bookmarkId) > 1 ? `${entry.bookmarkId}:${entry.partUri}:${entry.markerByteStart}` : entry.bookmarkId;
372859
+ return buildDiscoveryItem(discoveryId, handle, info);
372733
372860
  });
372734
372861
  return buildDiscoveryResult({
372735
372862
  evaluatedRevision: this.context.currentPublicRevision(),
@@ -372799,6 +372926,9 @@ class V2BookmarksAdapter {
372799
372926
  if (findBookmarkEntry(this.context, input.newName)) {
372800
372927
  return failure10("INVALID_INPUT", `bookmarks.rename: bookmark "${input.newName}" already exists.`);
372801
372928
  }
372929
+ const ambiguity = ambiguousBookmarkIdFailure(this.context, entry);
372930
+ if (ambiguity)
372931
+ return failure10(ambiguity.code, ambiguity.message);
372802
372932
  if (options?.dryRun && options.changeMode !== "tracked") {
372803
372933
  return {
372804
372934
  success: true,
@@ -372823,6 +372953,9 @@ class V2BookmarksAdapter {
372823
372953
  if (!documentProtectionAllowsXmlRange(this.context, entry.partUri, entry.markerByteStart, entry.markerByteStart)) {
372824
372954
  return failure10("PERMISSION_DENIED", DOCUMENT_PROTECTION_MESSAGE);
372825
372955
  }
372956
+ const ambiguity = ambiguousBookmarkIdFailure(this.context, entry);
372957
+ if (ambiguity)
372958
+ return failure10(ambiguity.code, ambiguity.message);
372826
372959
  if (options?.dryRun && options.changeMode !== "tracked") {
372827
372960
  return {
372828
372961
  success: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.8.0-next.4",
3
+ "version": "1.8.0-next.5",
4
4
  "description": "Model Context Protocol server for SuperDoc, giving an AI agent tools to read and edit .docx files.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0",
@@ -24,13 +24,13 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
- "@superdoc/sdk": "2.21.0-next.4",
27
+ "@superdoc/sdk": "2.21.0-next.5",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.24.0-next.4",
33
- "@superdoc/docx-engine": "0.23.0-next.4",
32
+ "superdoc": "2.24.0-next.5",
33
+ "@superdoc/docx-engine": "0.23.0-next.5",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",