@superdoc/mcp 1.2.0-next.3 → 1.2.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 +140 -20
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31314,7 +31314,7 @@ var init_host = __esm(() => {
31314
31314
  });
31315
31315
 
31316
31316
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31317
- var SDK_VERSION = "2.15.0-next.3";
31317
+ var SDK_VERSION = "2.15.0-next.5";
31318
31318
 
31319
31319
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31320
31320
  import { chmodSync, existsSync } from "node:fs";
@@ -133951,6 +133951,50 @@ var init_note_xml_validation = __esm(() => {
133951
133951
  });
133952
133952
 
133953
133953
  // ../../../v2/document-compare/src/replayability.ts
133954
+ function preservedBookmarkRunTokens(xml) {
133955
+ const markerTags = [...xml.matchAll(/<([\w.-]+:)?bookmark(Start|End)\b[^<>]*?\/>/g)];
133956
+ const markerOpenings = [...xml.matchAll(/<(?:[\w.-]+:)?bookmark(?:Start|End)\b/g)];
133957
+ if (markerTags.length !== 2 || markerOpenings.length !== 2 || markerTags[0][2] !== "Start" || markerTags[1][2] !== "End")
133958
+ return null;
133959
+ let valid = true;
133960
+ let depth = 0;
133961
+ const markers = [];
133962
+ const parser = new import_saxes3.SaxesParser({
133963
+ xmlns: true,
133964
+ additionalNamespaces: replayAdditionalNamespaces(xml)
133965
+ });
133966
+ parser.on("error", () => {
133967
+ valid = false;
133968
+ });
133969
+ parser.on("opentag", (tag) => {
133970
+ depth += 1;
133971
+ if (tag.local !== "bookmarkStart" && tag.local !== "bookmarkEnd")
133972
+ return;
133973
+ const attributes = Object.values(tag.attributes);
133974
+ const id = attributes.find((attribute) => attribute.uri === W_NS && attribute.local === "id")?.value;
133975
+ const name = attributes.find((attribute) => attribute.uri === W_NS && attribute.local === "name")?.value ?? null;
133976
+ if (tag.uri !== W_NS || !tag.isSelfClosing || depth !== 2 || !id || !/^\d+$/.test(id) || tag.local === "bookmarkStart" && !name || tag.local === "bookmarkEnd" && name !== null)
133977
+ valid = false;
133978
+ markers.push({ kind: tag.local, id: id ?? "", name });
133979
+ });
133980
+ parser.on("closetag", () => {
133981
+ depth -= 1;
133982
+ });
133983
+ try {
133984
+ parser.write(`<replay>${xml}</replay>`).close();
133985
+ } catch {
133986
+ valid = false;
133987
+ }
133988
+ if (!valid || depth !== 0 || markers.length !== 2 || markers[0].kind !== "bookmarkStart" || markers[1].kind !== "bookmarkEnd" || markers[0].id !== markers[1].id)
133989
+ return null;
133990
+ return {
133991
+ startXml: markerTags[0][0],
133992
+ endXml: markerTags[1][0],
133993
+ leadingXml: xml.slice(0, markerTags[0].index),
133994
+ trailingXml: xml.slice(markerTags[1].index + markerTags[1][0].length),
133995
+ strippedXml: xml.slice(0, markerTags[0].index) + xml.slice(markerTags[0].index + markerTags[0][0].length, markerTags[1].index) + xml.slice(markerTags[1].index + markerTags[1][0].length)
133996
+ };
133997
+ }
133954
133998
  function replayAdditionalNamespaces(xml) {
133955
133999
  const implicitNamespaces = { w: W_NS };
133956
134000
  const firstElement = /<([A-Za-z_][\w.-]*)(?::[A-Za-z_][\w.-]*)?(?=[\s/>])/.exec(xml);
@@ -134550,13 +134594,14 @@ function validateRunContents(xml, options) {
134550
134594
  if (xml === "")
134551
134595
  return { ok: true };
134552
134596
  const replayXml = stripAllowedNoteReferences(xml, options);
134553
- if (replayXml === null || UNSUPPORTED_XML.test(replayXml) || RELATIONSHIP_REFERENCE.test(replayXml)) {
134597
+ const withoutBookmarks = replayXml !== null && /<(?:[\w.-]+:)?bookmark(?:Start|End)\b/.test(replayXml) ? preservedBookmarkRunTokens(replayXml)?.strippedXml ?? null : replayXml;
134598
+ if (withoutBookmarks === null || UNSUPPORTED_XML.test(withoutBookmarks) || RELATIONSHIP_REFERENCE.test(withoutBookmarks)) {
134554
134599
  return { ok: false, reason: "target runs require unsupported structural or relationship replay" };
134555
134600
  }
134556
- const namespaceResult = validateReplayNamespaces(replayXml, "target runs use namespace prefixes that cannot be replayed safely");
134601
+ const namespaceResult = validateReplayNamespaces(withoutBookmarks, "target runs use namespace prefixes that cannot be replayed safely");
134557
134602
  if (!namespaceResult.ok)
134558
134603
  return namespaceResult;
134559
- if (!parseDirectRunSequence(replayXml, false)) {
134604
+ if (!parseDirectRunSequence(withoutBookmarks, false)) {
134560
134605
  return { ok: false, reason: "target runs contain unsupported inline markup" };
134561
134606
  }
134562
134607
  return { ok: true };
@@ -134604,7 +134649,7 @@ var import_saxes3, UNSUPPORTED_XML, RELATIONSHIP_REFERENCE, W_NS = "http://schem
134604
134649
  var init_replayability = __esm(() => {
134605
134650
  init_note_xml_validation();
134606
134651
  import_saxes3 = __toESM(require_saxes(), 1);
134607
- UNSUPPORTED_XML = /<(?:[\w.-]+:)?(?:hyperlink|drawing|pict|object|fldSimple|fldChar|instrText|commentReference|commentRangeStart|commentRangeEnd|bookmarkStart|bookmarkEnd|permStart|permEnd|sdt|customXml|oMath|oMathPara|footnoteReference|endnoteReference|ins|del|moveFrom|moveTo|pPrChange|rPrChange|sectPr)\b/i;
134652
+ UNSUPPORTED_XML = /<(?:[\w.-]+:)?(?:hyperlink|drawing|pict|object|fldSimple|fldChar|instrText|commentReference|commentRangeStart|commentRangeEnd|permStart|permEnd|sdt|customXml|oMath|oMathPara|footnoteReference|endnoteReference|ins|del|moveFrom|moveTo|pPrChange|rPrChange|sectPr)\b/i;
134608
134653
  RELATIONSHIP_REFERENCE = /\s(?:r:id|r:embed|r:link)\s*=/i;
134609
134654
  DIRECT_RUN_PROPERTY_ELEMENTS = new Set([
134610
134655
  "rStyle",
@@ -220762,6 +220807,26 @@ function runComparePayloadInsertCommit(input, storyId, step2, changeMode, option
220762
220807
  });
220763
220808
  return withParagraphInsertionCatalogRefs(input, receipt2, paragraph.wordIds, storyId);
220764
220809
  }
220810
+ function unchangedBookmarkReferenceSteps(oldRuns, targetRuns) {
220811
+ const oldHasMarker = /<(?:[\w.-]+:)?bookmark(?:Start|End)\b/.test(oldRuns);
220812
+ const targetHasMarker = /<(?:[\w.-]+:)?bookmark(?:Start|End)\b/.test(targetRuns);
220813
+ if (!oldHasMarker && !targetHasMarker)
220814
+ return [];
220815
+ const oldBookmark = preservedBookmarkRunTokens(oldRuns);
220816
+ const targetBookmark = preservedBookmarkRunTokens(targetRuns);
220817
+ if (!oldBookmark || !targetBookmark || oldBookmark.startXml !== targetBookmark.startXml || oldBookmark.endXml !== targetBookmark.endXml || oldBookmark.leadingXml !== targetBookmark.leadingXml || oldBookmark.trailingXml !== targetBookmark.trailingXml)
220818
+ return null;
220819
+ const startBindings = replayFragmentNamespaceBindings(oldBookmark.startXml);
220820
+ const endBindings = replayFragmentNamespaceBindings(oldBookmark.endXml);
220821
+ const bookmarkBindings = { ...startBindings, ...endBindings };
220822
+ return [{
220823
+ kind: "bookmark-start",
220824
+ beforeXml: oldBookmark.startXml,
220825
+ afterXml: oldBookmark.startXml,
220826
+ beforeNamespaceBindings: bookmarkBindings,
220827
+ afterNamespaceBindings: bookmarkBindings
220828
+ }];
220829
+ }
220765
220830
  function runCompareBodyEditCommit(input, storyId, step2, changeMode, options, pushHistory, referenceSteps) {
220766
220831
  const { state, txId } = input;
220767
220832
  const partUri = storyPartUriFromStoryId2(storyId);
@@ -220779,6 +220844,14 @@ function runCompareBodyEditCommit(input, storyId, step2, changeMode, options, pu
220779
220844
  const pPrXml = findFirstElement(paraXml, "pPr")?.xml ?? "";
220780
220845
  const targetParagraphPropertiesXml = step2.targetParagraphPropertiesXml === undefined ? undefined : rewriteCanonicalWordprocessingPrefix(step2.targetParagraphPropertiesXml, paragraphWrapper.wordprocessingPrefix);
220781
220846
  const newRuns = rewriteCanonicalWordprocessingPrefix(step2.targetRunXml ?? renderParagraphRuns(step2.text), paragraphWrapper.wordprocessingPrefix);
220847
+ const openEnd = paragraphWrapper.contentStart;
220848
+ const closeStart = paraXml.lastIndexOf("</");
220849
+ const innerXml = closeStart > openEnd ? paraXml.slice(openEnd, closeStart) : "";
220850
+ const oldRunsRaw = stripElements(innerXml, "pPr");
220851
+ const stableBookmarkSteps = unchangedBookmarkReferenceSteps(oldRunsRaw, newRuns);
220852
+ if (stableBookmarkSteps === null && referenceSteps.length === 0)
220853
+ return rejected14(txId, "unsupported-context");
220854
+ const protectedReferenceSteps = [...referenceSteps, ...stableBookmarkSteps ?? []];
220782
220855
  let newParaXml;
220783
220856
  const createdRefs = [];
220784
220857
  if (changeMode === "tracked") {
@@ -220794,12 +220867,10 @@ function runCompareBodyEditCommit(input, storyId, step2, changeMode, options, pu
220794
220867
  storyId
220795
220868
  });
220796
220869
  }
220797
- const openEnd = paragraphWrapper.contentStart;
220798
- const closeStart = paraXml.lastIndexOf("</");
220799
- const innerXml = closeStart > openEnd ? paraXml.slice(openEnd, closeStart) : "";
220800
- const oldRunsRaw = stripElements(innerXml, "pPr");
220801
220870
  const oldRunsDel = oldRunsRaw.replace(/<((?:[\w.-]+:)?)t(\b[^>]*)>/g, "<$1delText$2>").replace(/<\/((?:[\w.-]+:)?)t>/g, "</$1delText>");
220802
- const protectedRuns = renderTrackedRunsWithProtectedReferences(oldRunsRaw, newRuns, referenceSteps, stamps, paragraphWrapper.wordprocessingPrefix);
220871
+ const protectedRuns = renderTrackedRunsWithProtectedReferences(oldRunsRaw, newRuns, protectedReferenceSteps, stamps, paragraphWrapper.wordprocessingPrefix);
220872
+ if (!protectedRuns && stableBookmarkSteps?.length)
220873
+ return rejected14(txId, "unsupported-context");
220803
220874
  const delXml = protectedRuns?.xml ?? (oldRunsDel ? wrapTracked("del", oldRunsDel, stamps.del, "rsidDel", paragraphWrapper.wordprocessingPrefix) : "");
220804
220875
  const insXml = protectedRuns ? "" : newRuns ? wrapTracked("ins", newRuns, stamps.ins, "rsidR", paragraphWrapper.wordprocessingPrefix) : "";
220805
220876
  const trackedPPrXml = buildTrackedParagraphProperties(targetParagraphPropertiesXml, pPrXml, stamps.paragraphProperties ?? stamps.ins, paragraphWrapper.wordprocessingPrefix);
@@ -220883,6 +220954,10 @@ function runCompareBodyFormatEditCommit(input, storyId, step2, changeMode, optio
220883
220954
  const innerXml = closeStart > openEnd ? paraXml.slice(openEnd, closeStart) : "";
220884
220955
  const oldRunsRaw = stripElements(innerXml, "pPr");
220885
220956
  const paragraphPropertiesChanged = !equivalentParagraphProperties(targetPPrXml, pPrXml);
220957
+ const stableBookmarkSteps = unchangedBookmarkReferenceSteps(oldRunsRaw, targetRunXml);
220958
+ if (stableBookmarkSteps === null && referenceSteps.length === 0)
220959
+ return rejected14(txId, "unsupported-context");
220960
+ const protectedReferenceSteps = [...referenceSteps, ...stableBookmarkSteps ?? []];
220886
220961
  const baseSimpleRuns = scanSimpleRunFormatting(oldRunsRaw);
220887
220962
  const targetSimpleRuns = scanSimpleRunFormatting(targetRunXml);
220888
220963
  const paragraphPropertiesOnly = paragraphPropertiesChanged && baseSimpleRuns?.text === targetSimpleRuns?.text && computeRunSignature(targetRunXml) === computeRunSignature(oldRunsRaw);
@@ -220946,7 +221021,9 @@ function runCompareBodyFormatEditCommit(input, storyId, step2, changeMode, optio
220946
221021
  if (!stamps)
220947
221022
  return rejected14(txId, "no-author-configured");
220948
221023
  const oldRunsDel = oldRunsRaw.replace(/<((?:[\w.-]+:)?)t(\b[^>]*)>/g, "<$1delText$2>").replace(/<\/((?:[\w.-]+:)?)t>/g, "</$1delText>");
220949
- const protectedRuns = renderTrackedRunsWithProtectedReferences(oldRunsRaw, targetRunXml, referenceSteps, stamps, paragraphWrapper.wordprocessingPrefix);
221024
+ const protectedRuns = renderTrackedRunsWithProtectedReferences(oldRunsRaw, targetRunXml, protectedReferenceSteps, stamps, paragraphWrapper.wordprocessingPrefix);
221025
+ if (!protectedRuns && stableBookmarkSteps?.length)
221026
+ return rejected14(txId, "unsupported-context");
220950
221027
  const delXml = protectedRuns?.xml ?? (oldRunsDel ? wrapTracked("del", oldRunsDel, stamps.del, "rsidDel", paragraphWrapper.wordprocessingPrefix) : "");
220951
221028
  const insXml = protectedRuns ? "" : targetRunXml ? wrapTracked("ins", targetRunXml, stamps.ins, "rsidR", paragraphWrapper.wordprocessingPrefix) : "";
220952
221029
  if (delXml || insXml) {
@@ -246944,7 +247021,7 @@ function prepareHistoryReplayMutation(state, entry, direction, patchGroup) {
246944
247021
  ...contentControlRewrite.addedBlockIds,
246945
247022
  ...contentControlRewrite.contentBlockIds,
246946
247023
  ...contentControlRewrite.leadingBlockIds
246947
- ])] : collectPatchGroupTargetBlockIds(patchGroup);
247024
+ ])] : patchGroup.source.kind === "compareApply" ? [...new Set(patchGroup.source.bodySteps.map((step2) => step2.blockId))] : collectPatchGroupTargetBlockIds(patchGroup);
246948
247025
  const currentBaseRevisions = {
246949
247026
  package: state.packageRevision,
246950
247027
  perPart: {}
@@ -247198,6 +247275,8 @@ function collectPatchGroupTargetBlockIds(patchGroup) {
247198
247275
  return [...blockIds];
247199
247276
  }
247200
247277
  function inferHistoryStorySurfaceFamily(sourceKind) {
247278
+ if (sourceKind === "compareApply")
247279
+ return "compareApply";
247201
247280
  if (sourceKind === "editText")
247202
247281
  return "storyText";
247203
247282
  if (sourceKind.startsWith("list"))
@@ -424884,7 +424963,7 @@ function hasStrictMirrorPrerequisites(prepared, options) {
424884
424963
  case "storyAnchor":
424885
424964
  return options.session != null;
424886
424965
  case "compareApply":
424887
- return false;
424966
+ return options.session != null;
424888
424967
  default: {
424889
424968
  const exhaustive = extension2.family;
424890
424969
  return exhaustive;
@@ -424982,13 +425061,24 @@ function runFamilyMirror(prepared, extension2, options, directStoryText, tracked
424982
425061
  return mirrorPreparedTrackedDecide(prepared, trackedDecision);
424983
425062
  }
424984
425063
  if (extension2.family === "compareApply") {
424985
- return {
424986
- mirrored: false,
424987
- failure: {
424988
- storyId: prepared.resolvedTargets.stories[0] ?? "",
424989
- message: "story-surface mirror for the compareApply family is not supported (apply-deferred)"
424990
- }
424991
- };
425064
+ if (!options.session) {
425065
+ return {
425066
+ mirrored: false,
425067
+ mirrorPath: "session-sync",
425068
+ failure: {
425069
+ storyId: prepared.resolvedTargets.stories[0] ?? "",
425070
+ message: "compareApply session sync requires an authoritative session"
425071
+ }
425072
+ };
425073
+ }
425074
+ const sessionSync = mirrorStorySurfaceFromSession({
425075
+ session: options.session,
425076
+ prepared,
425077
+ extension: extension2,
425078
+ storyIds: storyIdsRequiringShards(prepared, extension2),
425079
+ resolveStoryShard: options.resolveStoryShard
425080
+ });
425081
+ return { ...sessionSync, mirrorPath: "session-sync" };
424992
425082
  }
424993
425083
  if (extension2.family === "storyAnchor" && prepared.source.kind === "insertComment" && !prepared.source.materialize) {
424994
425084
  return mirrorPreparedCommentInsert(prepared, extension2, options);
@@ -425756,6 +425846,9 @@ function admitPreparedStorySurfaceMutation(prepared, options) {
425756
425846
  }
425757
425847
  if (!touchesOwnedStoryPart(prepared))
425758
425848
  return { ok: true };
425849
+ if (extension2.family === "compareApply") {
425850
+ return validateCompareApplySessionSync(prepared, extension2, options);
425851
+ }
425759
425852
  if (extension2.family === "storyText") {
425760
425853
  if (extension2.historyReplay || extension2.resyncFromSession || extension2.sessionSync) {
425761
425854
  return validateStoryTextSessionSync(prepared, extension2, options);
@@ -425824,6 +425917,32 @@ function admitPreparedStorySurfaceMutation(prepared, options) {
425824
425917
  }
425825
425918
  return { ok: true };
425826
425919
  }
425920
+ function validateCompareApplySessionSync(prepared, extension2, options) {
425921
+ const source = prepared.source;
425922
+ if (source.kind !== "compareApply" || !options.session) {
425923
+ return { ok: false, message: "compareApply session sync requires an authoritative session" };
425924
+ }
425925
+ if (options.isSessionProjectionCurrent?.() !== true) {
425926
+ return { ok: false, message: "compareApply requires a current collaborative session projection" };
425927
+ }
425928
+ const storyId = String(source.storyId);
425929
+ const ownership = prepared.resolvedTargets.storyPartOwnership;
425930
+ if (!extension2.storyLocal || prepared.resolvedTargets.stories.length !== 1 || String(prepared.resolvedTargets.stories[0]) !== storyId || ownership.length !== 1 || String(ownership[0]?.storyId) !== storyId || prepared.resolvedTargets.partUris.length !== 1 || String(prepared.resolvedTargets.partUris[0]) !== String(ownership[0]?.partUri)) {
425931
+ return { ok: false, message: "compareApply collaboration requires one owned story part" };
425932
+ }
425933
+ if (source.bodySteps.length === 0 || source.bodySteps.some((step3) => step3.kind !== "edit") || source.storyGroups?.length || source.storyPackageOperations?.length || source.commentSteps?.length || source.packageRewrites?.length || source.relationshipBackedBodyRewrites?.length || source.headerFooterLifecycle || source.headerFooterSlotSteps?.length || source.tableTopologySteps?.length || source.tableBlockSteps?.length || source.tablePropertySteps?.length || source.sectionReplaySteps?.length || source.referenceReplaySteps?.length) {
425934
+ return { ok: false, message: "compareApply collaboration supports paragraph text edits only" };
425935
+ }
425936
+ const targetBlockIds2 = [...new Set(source.bodySteps.map((step3) => step3.blockId))];
425937
+ if (targetBlockIds2.length !== extension2.targetBlockIds.length || targetBlockIds2.some((blockId) => !extension2.targetBlockIds.includes(blockId))) {
425938
+ return { ok: false, message: "compareApply target blocks do not match its prepared refresh scope" };
425939
+ }
425940
+ const shard = options.resolveStoryShard(storyId);
425941
+ if (!shard || targetBlockIds2.some((blockId) => !findBlockMap(shard, blockId))) {
425942
+ return { ok: false, message: "compareApply target blocks are missing from the story shard" };
425943
+ }
425944
+ return { ok: true };
425945
+ }
425827
425946
  function validateStoryTextSessionSync(prepared, extension2, options) {
425828
425947
  if (!options.session) {
425829
425948
  return { ok: false, message: "storyText session sync requires an authoritative session" };
@@ -427460,6 +427579,7 @@ function createCollabV2SessionProjectionController(options) {
427460
427579
  const storyBackend = createStorySurfaceExecutionBackend({
427461
427580
  delegate: packageBackend,
427462
427581
  session: options.session,
427582
+ isSessionProjectionCurrent: () => !destroyed && !remoteProjectionPending && !deferredSessionAuthoritativeRemotePending && sessionStoryAlignment === "aligned",
427463
427583
  resolveStoryShard(storyId) {
427464
427584
  const handle = options.dispatcherRegistry.findStoryShardByStoryId?.(storyId);
427465
427585
  return handle ? collabUnitTargetOrDoc(handle) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.2.0-next.3",
3
+ "version": "1.2.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.15.0-next.3",
27
+ "@superdoc/sdk": "2.15.0-next.5",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.18.0-next.3",
33
- "@superdoc/docx-engine": "0.17.0-next.3",
32
+ "superdoc": "2.18.0-next.5",
33
+ "@superdoc/docx-engine": "0.17.0-next.6",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",