@superdoc/mcp 1.2.0-next.14 → 1.2.0-next.15

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 +196 -21
  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.14";
31317
+ var SDK_VERSION = "2.15.0-next.15";
31318
31318
 
31319
31319
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31320
31320
  import { chmodSync, existsSync } from "node:fs";
@@ -142181,6 +142181,12 @@ function visitNumericXmlIds(xml, visit) {
142181
142181
  if (value !== null)
142182
142182
  visit(value);
142183
142183
  }
142184
+ CONTENT_CONTROL_ID_RE.lastIndex = 0;
142185
+ while (match = CONTENT_CONTROL_ID_RE.exec(xml)) {
142186
+ const value = parseRevisionWId(decodeXmlTextPreservingInvalidNumericEntities(match[2] ?? ""));
142187
+ if (value !== null)
142188
+ visit(value);
142189
+ }
142184
142190
  }
142185
142191
  function scanMaxNumericXmlId(xml) {
142186
142192
  let max = 0;
@@ -142209,12 +142215,13 @@ function observeRevisionWIdsFromXml(state, xml) {
142209
142215
  if (max > reservation.max)
142210
142216
  reservation.max = max;
142211
142217
  }
142212
- var TD8, NUMERIC_XML_ID_RE;
142218
+ var TD8, NUMERIC_XML_ID_RE, CONTENT_CONTROL_ID_RE;
142213
142219
  var init_revision_wid_scan = __esm(() => {
142214
142220
  init_src2();
142215
142221
  init_xml_text();
142216
142222
  TD8 = new TextDecoder;
142217
142223
  NUMERIC_XML_ID_RE = /\b(?:[\w.-]+:)?id\s*=\s*(["'])([^"']*)\1/g;
142224
+ CONTENT_CONTROL_ID_RE = /<(?:[\w.-]+:)?id(?=[\s/>])[^>]*?\b(?:[\w.-]+:)?val\s*=\s*(["'])([^"']*)\1/g;
142218
142225
  });
142219
142226
 
142220
142227
  // ../../../v2/editor-core/dist/document/internal/part-wml-bookmark-start-cache.js
@@ -209410,6 +209417,17 @@ function planCut(pieces, levelStart, input, rootPieces, chain = []) {
209410
209417
  { close: chunks.close, reopen: chunks.open }
209411
209418
  ]);
209412
209419
  }
209420
+ if (strict.kind === "container" && strict.containerKind === "sdt" && input.allowMetadataAnchorSplit) {
209421
+ if (input.space === "tracked")
209422
+ return { kind: "reject", reason: "paragraph-split-point-unsupported" };
209423
+ const chunks = anchoredMetadataChunks(strict, input.allocateWId);
209424
+ if (!chunks)
209425
+ return { kind: "reject", reason: "paragraph-split-point-unsupported" };
209426
+ return planCut(strict.children, chunks.contentStart, input, rootPieces, [
209427
+ ...chain,
209428
+ { close: chunks.close, reopen: chunks.reopen }
209429
+ ]);
209430
+ }
209413
209431
  return { kind: "reject", reason: "paragraph-split-point-unsupported" };
209414
209432
  }
209415
209433
  let boundaryChar = levelStart;
@@ -209458,6 +209476,32 @@ function wrapperChunks(piece) {
209458
209476
  contentStart: piece.charStart + openEnd
209459
209477
  };
209460
209478
  }
209479
+ function anchoredMetadataChunks(piece, allocateWId) {
209480
+ if (piece.children.length === 0)
209481
+ return null;
209482
+ const raw = piece.rawXml;
209483
+ const prefix = /^(<w:sdt\b[^>]*>)\s*(<w:sdtPr>[\s\S]*?<\/w:sdtPr>)\s*(<w:sdtContent\b[^>]*>)/.exec(raw);
209484
+ const close = /<\/w:sdtContent>\s*<\/w:sdt>$/.exec(raw)?.[0];
209485
+ if (!prefix || !close)
209486
+ return null;
209487
+ const properties = prefix[2];
209488
+ const normalizedProperties = properties.replace(/\s+\/>/g, "/>").replace(/>\s+</g, "><");
209489
+ const id = /<w:id w:val="\d+"\/>/.exec(normalizedProperties)?.[0];
209490
+ const originalId = /<w:id w:val="\d+"\s*\/>/.exec(properties)?.[0];
209491
+ const alias = '<w:alias w:val="Anchored metadata"/>';
209492
+ const tag = /<w:tag w:val="[^"]+"\/>/.exec(normalizedProperties)?.[0];
209493
+ const appearance = '<w15:appearance w15:val="hidden"/>';
209494
+ const plainText = "<w:text/>";
209495
+ if (!id || !originalId || !tag || !normalizedProperties.includes(alias) || !normalizedProperties.includes(appearance) || !normalizedProperties.includes(plainText) || normalizedProperties !== `<w:sdtPr>${id}${alias}${tag}${appearance}${plainText}</w:sdtPr>`) {
209496
+ return null;
209497
+ }
209498
+ const originalPrefix = prefix[0];
209499
+ return {
209500
+ contentStart: piece.charStart + originalPrefix.length,
209501
+ close,
209502
+ reopen: () => originalPrefix.replace(originalId, originalId.replace(/(w:val=")\d+/, (_match, attribute) => `${attribute}${allocateWId()}`))
209503
+ };
209504
+ }
209461
209505
  function openTagEnd(raw) {
209462
209506
  let quote = null;
209463
209507
  for (let i2 = 0;i2 < raw.length; i2 += 1) {
@@ -209484,7 +209528,7 @@ function refreshRevisionId(openChunk, allocateWId) {
209484
209528
  }
209485
209529
  function assembleHalves(src, regionStart, regionEnd, plan) {
209486
209530
  const closes = [...plan.chain].reverse().map((element) => element.close).join("");
209487
- const reopens = plan.chain.map((element) => element.reopen).join("");
209531
+ const reopens = plan.chain.map((element) => typeof element.reopen === "function" ? element.reopen() : element.reopen).join("");
209488
209532
  if (plan.kind === "boundary") {
209489
209533
  const boundaryChar = snapBoundaryPastRunClose(src, plan.boundaryChar, regionEnd);
209490
209534
  return {
@@ -213749,7 +213793,8 @@ function prepareParagraphSplit(input) {
213749
213793
  offset: input.offset,
213750
213794
  space: input.coordinateSpace,
213751
213795
  allocateWId: input.allocateWId,
213752
- atomicObjectsAsCaretSlots: true
213796
+ atomicObjectsAsCaretSlots: true,
213797
+ allowMetadataAnchorSplit: true
213753
213798
  });
213754
213799
  if (!slice.ok)
213755
213800
  return slice;
@@ -213772,6 +213817,14 @@ function prepareParagraphSplit(input) {
213772
213817
  const headXml = openTag + headProperties + slice.head + closeTag;
213773
213818
  return { ok: true, headXml, tailXml };
213774
213819
  }
213820
+ function previewParagraphSplit(input) {
213821
+ const result = prepareParagraphSplit({
213822
+ ...input,
213823
+ tailParaId: "00000000",
213824
+ allocateWId: () => 0
213825
+ });
213826
+ return result.ok ? { ok: true } : result;
213827
+ }
213775
213828
  function renderPreparedParagraphSplit(split, trackedStamp) {
213776
213829
  const head = trackedStamp ? injectParagraphMarkTrackedMarker(split.headXml, "ins", trackedStamp) : split.headXml;
213777
213830
  return head + split.tailXml;
@@ -267816,6 +267869,10 @@ var init_registry3 = __esm(() => {
267816
267869
  "blocks.move": {
267817
267870
  supportsDryRun: true,
267818
267871
  dryRunOverrideReason: "The V2 block adapter validates move previews without committing package or history state."
267872
+ },
267873
+ "blocks.split": {
267874
+ supportsDryRun: true,
267875
+ dryRunOverrideReason: "The V2 block adapter validates split previews without committing package or history state."
267819
267876
  }
267820
267877
  };
267821
267878
  COLLABORATIVE_TABLE_REPRESENTED_OPERATIONS = new Set([
@@ -303692,17 +303749,35 @@ class V2BlocksAdapter {
303692
303749
  const resolved = resolveParagraphTarget(this.context, input.target);
303693
303750
  if ("error" in resolved)
303694
303751
  return failure4(resolved.error, resolved.message);
303695
- const begun = this.context.beginMutation({ expectedRevision: options?.expectedRevision });
303696
- if ("failure" in begun)
303697
- return failure4(begun.failure.code, begun.failure.message);
303698
- const tx = begun.tx;
303699
303752
  const partBytes = getSDDocumentSessionInternalPartBytes(this.context.session, storyPartUriFromId5(resolved.storyId));
303700
303753
  const paraXml = partBytes ? TD90.decode(partBytes.subarray(resolved.entry.byteStart, resolved.entry.byteEnd)) : "";
303701
303754
  const objectSlack = (paraXml.match(/<[\w.-]+:(?:drawing|pict|object)\b/g) ?? []).length;
303702
303755
  const coordinateSpace = input.coordinateSpace ?? "visible";
303756
+ const offset = coordinateSpace === "tracked" ? Math.max(0, Math.trunc(Number.isFinite(input.offset) ? input.offset : 0)) : clampStructuralOffset(input.offset, resolved.entry.textLength + objectSlack);
303757
+ if (options?.dryRun) {
303758
+ const policy = this.context.validateMutation(options);
303759
+ if (policy)
303760
+ return failure4(policy.code, policy.message);
303761
+ if (!partBytes)
303762
+ return failure4("INVALID_CONTEXT", "paragraph-target-not-found");
303763
+ const planned = previewParagraphSplit({
303764
+ paragraphXml: paraXml,
303765
+ partBytes,
303766
+ paragraphByteStart: resolved.entry.byteStart,
303767
+ offset,
303768
+ coordinateSpace
303769
+ });
303770
+ if (!planned.ok)
303771
+ return failure4(mapRejectionReason(planned.reason), planned.reason);
303772
+ return { success: true, inserted: input.target, affectedStories: [] };
303773
+ }
303774
+ const begun = this.context.beginMutation({ expectedRevision: options?.expectedRevision });
303775
+ if ("failure" in begun)
303776
+ return failure4(begun.failure.code, begun.failure.message);
303777
+ const tx = begun.tx;
303703
303778
  tx.paragraphSplit({
303704
303779
  target: { storyId: resolved.storyId, paraId: input.target.nodeId },
303705
- offset: coordinateSpace === "tracked" ? Math.max(0, Math.trunc(Number.isFinite(input.offset) ? input.offset : 0)) : clampStructuralOffset(input.offset, resolved.entry.textLength + objectSlack),
303780
+ offset,
303706
303781
  coordinateSpace,
303707
303782
  changeMode: options?.changeMode ?? "direct"
303708
303783
  });
@@ -359147,9 +359222,14 @@ function buildTrackedTableRowReplayPlan(input) {
359147
359222
  if (baseTable.gridColumnCount !== targetTable.gridColumnCount) {
359148
359223
  return unsafe(`table ${baseTable.tableNodeId} changes its column grid`);
359149
359224
  }
359150
- const rowKey = (row, bytes) => sliceBytes(bytes, row.rowByteStart, row.rowByteEnd).replace(/\s+w14:paraId="[0-9A-Fa-f]{8}"/g, "");
359151
- const baseKeys = baseTable.rows.map((row) => rowKey(row, baseBytes));
359152
- const targetKeys = targetTable.rows.map((row) => rowKey(row, targetBytes));
359225
+ const rowKey = (row, bytes, root) => rowWithoutParagraphIdentities(sliceBytes(bytes, row.rowByteStart, row.rowByteEnd), root.namespaceBindings);
359226
+ const baseKeysWithInvalid = baseTable.rows.map((row) => rowKey(row, baseBytes, baseRoot));
359227
+ const targetKeysWithInvalid = targetTable.rows.map((row) => rowKey(row, targetBytes, targetRoot));
359228
+ if (baseKeysWithInvalid.includes(null) || targetKeysWithInvalid.includes(null)) {
359229
+ return unsafe(`table ${baseTable.tableNodeId} has invalid paragraph identity markup`);
359230
+ }
359231
+ const baseKeys = baseKeysWithInvalid.map((key2) => key2);
359232
+ const targetKeys = targetKeysWithInvalid.map((key2) => key2);
359153
359233
  const baseIsShorter = baseKeys.length <= targetKeys.length;
359154
359234
  const matched = matchRowSubsequence(baseIsShorter ? baseKeys : targetKeys, baseIsShorter ? targetKeys : baseKeys, (baseIsShorter ? baseTable.rows : targetTable.rows).map((row) => row.rowNodeId), (baseIsShorter ? targetTable.rows : baseTable.rows).map((row) => row.rowNodeId));
359155
359235
  if (!matched)
@@ -359427,6 +359507,66 @@ function tableSkeleton(bytes, table) {
359427
359507
  function sliceBytes(bytes, start, end) {
359428
359508
  return new TextDecoder().decode(bytes.subarray(start, end));
359429
359509
  }
359510
+ function rowWithoutParagraphIdentities(rowXml, namespaceBindings) {
359511
+ const parsed = collectXmlElementRanges(rowXml, {
359512
+ fragment: true,
359513
+ additionalNamespaces: xmlFragmentAdditionalNamespaces(rowXml, new Map(Object.entries(namespaceBindings)))
359514
+ });
359515
+ if (parsed.errors.length > 0)
359516
+ return null;
359517
+ const deletions = [];
359518
+ for (const paragraph4 of parsed.ranges) {
359519
+ if (paragraph4.tag.namespaceUri !== WORDPROCESSINGML_NS4 || paragraph4.tag.localName !== "p")
359520
+ continue;
359521
+ for (const attribute2 of paragraph4.tag.attributes) {
359522
+ if (attribute2.namespaceUri !== WORDPROCESSINGML_2010_NS || attribute2.localName !== "paraId" || !/^[0-9A-Fa-f]{8}$/.test(attribute2.value))
359523
+ continue;
359524
+ const opening = rowXml.slice(paragraph4.start, paragraph4.openEnd);
359525
+ const span = rawStartTagAttributeSpan(opening, attribute2.name, attribute2.value);
359526
+ if (!span)
359527
+ return null;
359528
+ deletions.push({ start: paragraph4.start + span.start, end: paragraph4.start + span.end });
359529
+ }
359530
+ }
359531
+ return deletions.sort((left, right) => right.start - left.start).reduce((xml, deletion) => xml.slice(0, deletion.start) + xml.slice(deletion.end), rowXml);
359532
+ }
359533
+ function rawStartTagAttributeSpan(opening, expectedName, expectedValue) {
359534
+ const whitespace = (character) => character !== undefined && /[\x20\t\r\n]/.test(character);
359535
+ let index2 = 1;
359536
+ while (index2 < opening.length && !whitespace(opening[index2]) && opening[index2] !== ">" && opening[index2] !== "/")
359537
+ index2 += 1;
359538
+ while (index2 < opening.length) {
359539
+ const start = index2;
359540
+ while (whitespace(opening[index2]))
359541
+ index2 += 1;
359542
+ if (opening[index2] === ">" || opening[index2] === "/")
359543
+ break;
359544
+ const nameStart = index2;
359545
+ while (index2 < opening.length && !whitespace(opening[index2]) && !["=", ">", "/"].includes(opening[index2]))
359546
+ index2 += 1;
359547
+ const name = opening.slice(nameStart, index2);
359548
+ while (whitespace(opening[index2]))
359549
+ index2 += 1;
359550
+ if (opening[index2] !== "=")
359551
+ return null;
359552
+ index2 += 1;
359553
+ while (whitespace(opening[index2]))
359554
+ index2 += 1;
359555
+ const quote = opening[index2];
359556
+ if (quote !== '"' && quote !== "'")
359557
+ return null;
359558
+ const valueStart = ++index2;
359559
+ while (index2 < opening.length && opening[index2] !== quote)
359560
+ index2 += 1;
359561
+ if (index2 === opening.length)
359562
+ return null;
359563
+ const value2 = opening.slice(valueStart, index2);
359564
+ index2 += 1;
359565
+ if (name === expectedName && value2 === expectedValue)
359566
+ return { start, end: index2 };
359567
+ }
359568
+ return null;
359569
+ }
359430
359570
  function documentRootContext(xml) {
359431
359571
  const roots = [];
359432
359572
  let valid = true;
@@ -363217,22 +363357,32 @@ function buildCompareApplyEligibility(context, payload, plans) {
363217
363357
  if (bodyDeferredToTableReplay)
363218
363358
  direct.add("body");
363219
363359
  }
363360
+ const trackedBodyOperations = payload.applyPlan.bodyOperations.length > 0 ? payload.applyPlan.bodyOperations : computeCompareBodyOperations(payload.base.body, payload.target.body, {
363361
+ base: payload.base.definitions,
363362
+ target: payload.target.definitions
363363
+ });
363220
363364
  const trackedTablePlan = buildTrackedTableRowReplayPlan({
363221
363365
  base: mainDocument.base,
363222
363366
  target: mainDocument.target,
363223
363367
  baseBody: payload.base.body,
363224
363368
  targetBody: payload.target.body,
363225
- bodyOperations: payload.applyPlan.bodyOperations.length > 0 ? payload.applyPlan.bodyOperations : computeCompareBodyOperations(payload.base.body, payload.target.body, {
363226
- base: payload.base.definitions,
363227
- target: payload.target.definitions
363228
- })
363369
+ bodyOperations: trackedBodyOperations
363229
363370
  });
363371
+ const trackedBlockPlan = trackedTablePlan.unsafeReasons.length > 0 && !trackedTablePlan.refuseBlockFallback ? buildTrackedTableBlockReplayPlan({
363372
+ base: mainDocument.base,
363373
+ target: mainDocument.target,
363374
+ bodyOperations: trackedBodyOperations,
363375
+ allowTopologyReplacement: true
363376
+ }) : null;
363230
363377
  if (trackedTablePlan.unsafeReasons.length === 0 && trackedTablePlan.steps.length > 0) {
363231
363378
  tracked.add("tables");
363232
363379
  if (bodyDeferredToTableReplay)
363233
363380
  tracked.add("body");
363234
363381
  if (rowReplayCoversContentControls(payload.base.annotations, payload.target.annotations, trackedTablePlan.steps, mainDocument.base.xml, mainDocument.target.xml))
363235
363382
  tracked.add("content-controls");
363383
+ } else if (trackedBlockPlan && trackedBlockPlan.steps.length > 0) {
363384
+ tracked.add("tables");
363385
+ tracked.add("body");
363236
363386
  }
363237
363387
  }
363238
363388
  const packageGraphCoveredByComments = direct.has("comments") && packageGraphKeysNotCoveredByComments(context, payload.base, payload.target, plans.commentPlan.steps).length === 0;
@@ -381916,10 +382066,27 @@ function groupMetadataAnchor(documentXml, id, knownIds) {
381916
382066
  const kept = contiguousAnchorPrefix(documentXml, matches);
381917
382067
  if (kept.length === 1)
381918
382068
  return { id, segments: kept, target: kept[0].target };
381919
- const textSegments = kept.map((anchor) => ({
381920
- blockId: anchor.blockId,
381921
- range: { start: anchor.startOffset, end: anchor.endOffset }
381922
- }));
382069
+ const textSegments = [];
382070
+ for (const anchor of kept) {
382071
+ const previous3 = textSegments.at(-1);
382072
+ if (previous3?.blockId === anchor.blockId && previous3.range.end === anchor.startOffset) {
382073
+ previous3.range.end = anchor.endOffset;
382074
+ } else {
382075
+ textSegments.push({ blockId: anchor.blockId, range: { start: anchor.startOffset, end: anchor.endOffset } });
382076
+ }
382077
+ }
382078
+ if (textSegments.length === 1) {
382079
+ const range = textSegments[0];
382080
+ return {
382081
+ id,
382082
+ segments: kept,
382083
+ target: {
382084
+ kind: "selection",
382085
+ start: { kind: "text", blockId: range.blockId, offset: range.range.start, story: bodyStoryLocator2() },
382086
+ end: { kind: "text", blockId: range.blockId, offset: range.range.end, story: bodyStoryLocator2() }
382087
+ }
382088
+ };
382089
+ }
381923
382090
  return {
381924
382091
  id,
381925
382092
  segments: kept,
@@ -381939,7 +382106,12 @@ function contiguousAnchorPrefix(documentXml, matches) {
381939
382106
  const context = map3.byBlockId(matches[i2].blockId);
381940
382107
  if (!context)
381941
382108
  break;
381942
- if (context.ordinal !== prev.ordinal + 1)
382109
+ const sameParagraph = context.ordinal === prev.ordinal;
382110
+ if (sameParagraph) {
382111
+ const previousAnchor = kept.at(-1);
382112
+ if (context.blockId !== previousAnchor.blockId || matches[i2].startOffset !== previousAnchor.endOffset || !isMetadataCarrierGap(documentXml.slice(previousAnchor.end, matches[i2].start)))
382113
+ break;
382114
+ } else if (context.ordinal !== prev.ordinal + 1)
381943
382115
  break;
381944
382116
  if (!sameTableCellPath(context.tableCellPath, first.tableCellPath))
381945
382117
  break;
@@ -381956,6 +382128,9 @@ function contiguousAnchorPrefix(documentXml, matches) {
381956
382128
  }
381957
382129
  return kept;
381958
382130
  }
382131
+ function isMetadataCarrierGap(xml) {
382132
+ return /^(?:\s*<w:proofErr\s+w:type="(?:spellStart|spellEnd|gramStart|gramEnd)"\s*\/>)*\s*$/.test(xml);
382133
+ }
381959
382134
  function sameOrdinalPath2(left, right) {
381960
382135
  return left.length === right.length && left.every((value2, index2) => value2 === right[index2]);
381961
382136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.2.0-next.14",
3
+ "version": "1.2.0-next.15",
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.14",
27
+ "@superdoc/sdk": "2.15.0-next.15",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.18.0-next.14",
33
- "@superdoc/docx-engine": "0.17.0-next.16",
32
+ "superdoc": "2.18.0-next.15",
33
+ "@superdoc/docx-engine": "0.17.0-next.17",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",