@superdoc/mcp 1.7.0-next.12 → 1.7.0-next.14

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 +399 -53
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -31600,7 +31600,7 @@ var init_host = __esm(() => {
31600
31600
  });
31601
31601
 
31602
31602
  // ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
31603
- var SDK_VERSION = "2.20.0-next.12";
31603
+ var SDK_VERSION = "2.20.0-next.14";
31604
31604
 
31605
31605
  // ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
31606
31606
  import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
@@ -202834,6 +202834,18 @@ function commitTracked(input, view) {
202834
202834
  newText: op.newText,
202835
202835
  allocateWIdBlock: allocateLocalizedWIdBlock
202836
202836
  }, inlineContext, namespaceBindings);
202837
+ const refinementStart = compileOp.on.coordinateSpace === "tracked" ? projectTrackedParagraphOffsetToVisible(paragraphXml, compileOp.on.startOffset) : compileOp.on.startOffset;
202838
+ const refinementEnd = compileOp.on.coordinateSpace === "tracked" ? projectTrackedParagraphOffsetToVisible(paragraphXml, compileOp.on.endOffset) : compileOp.on.endOffset;
202839
+ const ownLinkedRefinement = refinementStart !== null && refinementEnd !== null ? refineOwnLinkedInsertion(inlineModel, refinementStart, refinementEnd, op.newText, stamping.author, state) : null;
202840
+ if (ownLinkedRefinement) {
202841
+ localized = {
202842
+ ok: true,
202843
+ bytes: TE17.encode(ownLinkedRefinement.xml),
202844
+ emittedBothSides: false,
202845
+ foldedInsRsid: ownLinkedRefinement.rsid,
202846
+ requiresCollaborationSessionSync: true
202847
+ };
202848
+ }
202837
202849
  const canSpanningDelete = compileOp.on.coordinateSpace !== "tracked" && op.newText.length === 0 && compileOp.on.startOffset < compileOp.on.endOffset;
202838
202850
  const spanningDeleteWIds = [];
202839
202851
  let usedSpanningDelete = false;
@@ -202971,6 +202983,17 @@ function commitTracked(input, view) {
202971
202983
  },
202972
202984
  primaryBytes: localized.bytes,
202973
202985
  rewrite: (paragraphBytes2, paragraphWindow) => {
202986
+ if (ownLinkedRefinement) {
202987
+ const counterpartXml = TD42.decode(paragraphBytes2.subarray(paragraphWindow.byteStart, paragraphWindow.byteEnd));
202988
+ const refinement = refineOwnLinkedInsertion(parseParagraphInlineMap(counterpartXml, namespaceBindings), refinementStart, refinementEnd, op.newText, stamping.author, state);
202989
+ return refinement ? {
202990
+ ok: true,
202991
+ bytes: TE17.encode(refinement.xml),
202992
+ emittedBothSides: false,
202993
+ foldedInsRsid: refinement.rsid,
202994
+ requiresCollaborationSessionSync: true
202995
+ } : { ok: false, reason: "textbox-counterpart-ambiguous" };
202996
+ }
202974
202997
  let additionalWIdIndex = 0;
202975
202998
  const base2 = rewriteLocalizedTracked(paragraphBytes2, paragraphWindow, compileOp, {
202976
202999
  rsid: op.rsid,
@@ -206222,6 +206245,80 @@ function containsOnlyTrackedWrappersAndZeroWidth(xml) {
206222
206245
  return false;
206223
206246
  return containsOnlyZeroWidthParagraphTail(withoutWrappers);
206224
206247
  }
206248
+ function refineOwnLinkedInsertion(model, start, end, newText, author, state) {
206249
+ if (newText.includes("\t"))
206250
+ return null;
206251
+ const wrapper = model.pieces.find((piece) => piece.kind === "tracked" && piece.trackedKind === "ins" && piece.visibleStart <= start && piece.visibleEnd >= end);
206252
+ if (!wrapper || wrapper.kind !== "tracked" || !wrapper.children.some((piece) => piece.kind === "container" && piece.containerKind === "complexField") || !wrapper.rsid || !collectSessionCreatedTrackedChangeRsids(state).has(wrapper.rsid) || wrapper.revisionId === null || !collectSessionCreatedTrackedChangeWIds(state).has(Number(wrapper.revisionId)) || classifyInsertionAuthoringOwnership(buildReviewIdentity(author), buildReviewIdentity({
206253
+ name: wrapper.author,
206254
+ email: wrapper.email,
206255
+ initials: wrapper.initials
206256
+ })) !== "same-user")
206257
+ return null;
206258
+ const fields = [];
206259
+ const texts = [];
206260
+ for (const child of wrapper.children) {
206261
+ if (child.kind === "text" && child.textRole === "visible")
206262
+ texts.push(child);
206263
+ else if (child.kind === "container" && child.containerKind === "complexField" && child.resultCharStart !== undefined) {
206264
+ const instructions = child.children.filter((piece) => piece.kind === "text" && piece.textRole === "instruction");
206265
+ if (!/^HYPERLINK\s/i.test(instructions.map((piece) => piece.kind === "text" ? piece.decodedText : "").join("").trim()))
206266
+ return null;
206267
+ for (const piece of child.children) {
206268
+ if (piece.kind === "text") {
206269
+ if (piece.textRole === "visible")
206270
+ texts.push(piece);
206271
+ else if (piece.textRole !== "instruction")
206272
+ return null;
206273
+ } else if (piece.kind !== "marker" || piece.role !== "field")
206274
+ return null;
206275
+ }
206276
+ fields.push(child);
206277
+ } else
206278
+ return null;
206279
+ }
206280
+ if (!fields.length)
206281
+ return null;
206282
+ const paragraphXml = model.paragraphXml;
206283
+ if (start === wrapper.visibleStart && end === wrapper.visibleEnd && newText === "") {
206284
+ return { xml: paragraphXml.slice(0, wrapper.charStart) + paragraphXml.slice(wrapper.charEnd), rsid: wrapper.rsid };
206285
+ }
206286
+ const selected = start === end ? texts.filter((piece) => piece.visibleStart <= start && piece.visibleEnd >= start) : texts.filter((piece) => piece.visibleStart < end && piece.visibleEnd > start);
206287
+ const fieldFor = (piece) => fields.find((field2) => piece.charStart >= field2.resultCharStart && piece.charEnd <= field2.resultCharEnd);
206288
+ if (start === end) {
206289
+ const ordinary = selected.find((piece) => !fieldFor(piece));
206290
+ const interior = selected.find((piece) => piece.visibleStart < start && piece.visibleEnd > start);
206291
+ const chosen = ordinary ?? interior;
206292
+ if (!chosen)
206293
+ return null;
206294
+ selected.splice(0, selected.length, chosen);
206295
+ }
206296
+ const first = selected[0];
206297
+ const last = selected.at(-1);
206298
+ if (!first || !last || first.visibleStart > start || last.visibleEnd < end)
206299
+ return null;
206300
+ const field = fieldFor(first);
206301
+ if (selected.some((piece) => fieldFor(piece) !== field))
206302
+ return null;
206303
+ const patches = [];
206304
+ for (const [index, piece] of selected.entries()) {
206305
+ const tag = /^<([\w.-]+):t\b([^>]*)>[\s\S]*?<\/\1:t>$/.exec(piece.rawXml);
206306
+ if (!tag)
206307
+ return null;
206308
+ const localStart = Math.max(0, start - piece.visibleStart);
206309
+ const localEnd = Math.min(piece.decodedText.length, end - piece.visibleStart);
206310
+ const text = piece.decodedText.slice(0, localStart) + (index === 0 ? newText : "") + piece.decodedText.slice(localEnd);
206311
+ patches.push({
206312
+ start: piece.charStart,
206313
+ end: piece.charEnd,
206314
+ xml: `<${tag[1]}:t${preserveTextElementAttributes(tag[2], text)}>${escapeXmlText(text)}</${tag[1]}:t>`
206315
+ });
206316
+ }
206317
+ let rewritten = paragraphXml;
206318
+ for (const patch of patches.reverse())
206319
+ rewritten = rewritten.slice(0, patch.start) + patch.xml + rewritten.slice(patch.end);
206320
+ return { xml: rewritten, rsid: wrapper.rsid };
206321
+ }
206225
206322
  function spliceWithinSameAuthorInsertion(paragraphXml, startOffset, endOffset, newText, author) {
206226
206323
  const createdVisibleTextSpan = startOffset === endOffset && newText.length > 0 ? {
206227
206324
  startOffset,
@@ -207290,7 +207387,7 @@ function isolateSimpleTextRangeInParagraphXml(input) {
207290
207387
  if (input.rangeStart < 0 || input.rangeEnd <= input.rangeStart) {
207291
207388
  return { ok: false, reason: "invalid-range" };
207292
207389
  }
207293
- const contextualRejection = rejectSimpleTextRangeContext(input.paragraphXml, input.rangeStart, input.rangeEnd, input.allowDisjointTracked ?? false);
207390
+ const contextualRejection = rejectSimpleTextRangeContext(input.paragraphXml, input.rangeStart, input.rangeEnd, input.allowDisjointTracked ?? false, input.allowDisjointFields ?? false);
207294
207391
  if (contextualRejection)
207295
207392
  return { ok: false, reason: contextualRejection };
207296
207393
  const paragraphOpen = /^<([\w.-]+):p\b[^>]*>/.exec(input.paragraphXml);
@@ -207303,7 +207400,7 @@ function isolateSimpleTextRangeInParagraphXml(input) {
207303
207400
  }
207304
207401
  const runs = [];
207305
207402
  const runRe = /<([\w.-]+):r\b[^>]*>[\s\S]*?<\/\1:r>/g;
207306
- const ordinaryRunStarts = input.allowDisjointTracked ? new Map : null;
207403
+ const ordinaryRunStarts = input.allowDisjointTracked || input.allowDisjointFields ? new Map : null;
207307
207404
  if (ordinaryRunStarts) {
207308
207405
  for (const piece of parseParagraphInlineMap(input.paragraphXml).leaves()) {
207309
207406
  if (piece.kind === "text" && piece.textRole === "visible" && piece.containerStack.length === 0 && !ordinaryRunStarts.has(piece.runCharStart)) {
@@ -207378,9 +207475,11 @@ function renderSimpleTextRunSlice(slice, options = {}) {
207378
207475
  }).join("");
207379
207476
  return `${slice.runOpenTag}${options.rPrXml ?? slice.rPrXml}${textXml}${slice.runCloseTag}`;
207380
207477
  }
207381
- function rejectSimpleTextRangeContext(paragraphXml, rangeStart, rangeEnd, allowDisjointTracked) {
207382
- if (/<[\w.-]+:(?:fldSimple|fldChar|instrText|delInstrText)\b/.test(paragraphXml))
207383
- return "field";
207478
+ function rejectSimpleTextRangeContext(paragraphXml, rangeStart, rangeEnd, allowDisjointTracked, allowDisjointFields) {
207479
+ if (/<[\w.-]+:(?:fldSimple|fldChar|instrText|delInstrText)\b/.test(paragraphXml)) {
207480
+ if (!allowDisjointFields || !hasOnlyDisjointFields(paragraphXml, rangeStart, rangeEnd))
207481
+ return "field";
207482
+ }
207384
207483
  if (/<[\w.-]+:(?:commentRangeStart|commentRangeEnd|commentReference)\b/.test(paragraphXml)) {
207385
207484
  return "comment";
207386
207485
  }
@@ -207402,6 +207501,34 @@ function rejectSimpleTextRangeContext(paragraphXml, rangeStart, rangeEnd, allowD
207402
207501
  return "drawing";
207403
207502
  return null;
207404
207503
  }
207504
+ function hasOnlyDisjointFields(paragraphXml, rangeStart, rangeEnd) {
207505
+ const fields = [];
207506
+ function visit(pieces) {
207507
+ for (const piece of pieces) {
207508
+ if (piece.kind !== "container")
207509
+ continue;
207510
+ if (piece.containerKind === "complexField" || piece.containerKind === "fldSimple") {
207511
+ if (rangeStart < piece.visibleEnd && rangeEnd > piece.visibleStart)
207512
+ return false;
207513
+ if (piece.containerKind === "complexField" && piece.resultCharStart === undefined)
207514
+ return false;
207515
+ fields.push({ start: piece.charStart, end: piece.charEnd });
207516
+ } else if (!visit(piece.children))
207517
+ return false;
207518
+ }
207519
+ return true;
207520
+ }
207521
+ if (!visit(parseParagraphInlineMap(paragraphXml).pieces))
207522
+ return false;
207523
+ let outsideFields = "";
207524
+ let cursor = 0;
207525
+ for (const field of fields) {
207526
+ outsideFields += paragraphXml.slice(cursor, field.start);
207527
+ cursor = field.end;
207528
+ }
207529
+ outsideFields += paragraphXml.slice(cursor);
207530
+ return !/<[\w.-]+:(?:fldSimple|fldChar|instrText|delInstrText)\b/.test(outsideFields);
207531
+ }
207405
207532
  function hasTrackedOverlap(pieces, rangeStart, rangeEnd) {
207406
207533
  for (const piece of pieces) {
207407
207534
  if (piece.kind === "tracked" && rangeStart < piece.visibleEnd && rangeEnd > piece.visibleStart) {
@@ -247417,6 +247544,80 @@ function runHyperlinkWrapCommit(input) {
247417
247544
  if (!bytes)
247418
247545
  return rejected19(input.txId, "hyperlink-target-not-found");
247419
247546
  const paraXml = TD71.decode(bytes.subarray(paragraph.byteStart, paragraph.byteEnd));
247547
+ const overlappingInsertions = parseParagraphInlineMap(paraXml).pieces.filter((piece) => piece.kind === "tracked" && piece.trackedKind === "ins" && piece.visibleStart < op.on.endOffset && piece.visibleEnd > op.on.startOffset);
247548
+ if (overlappingInsertions.length > 0) {
247549
+ if (overlappingInsertions.length !== 1)
247550
+ return rejected19(input.txId, "hyperlink-tracked-or-comment-unsupported");
247551
+ const insertion = overlappingInsertions[0];
247552
+ const revisionId = Number(insertion.revisionId);
247553
+ if (insertion.visibleStart > op.on.startOffset || insertion.visibleEnd < op.on.endOffset || !Number.isSafeInteger(revisionId) || !collectSessionCreatedTrackedChangeWIds(input.state).has(revisionId) || !insertion.rsid || !collectSessionCreatedTrackedChangeRsids(input.state).has(insertion.rsid) || classifyInsertionAuthoringOwnership(buildReviewIdentity(stamping.author), buildReviewIdentity({ name: insertion.author, email: insertion.email, initials: insertion.initials })) !== "same-user")
247554
+ return rejected19(input.txId, "hyperlink-tracked-or-comment-unsupported");
247555
+ const textbox = input.state.textboxRegistry.byStoryId.get(op.on.storyId);
247556
+ if (textbox && textbox.alternateContentCounterparts.length > 1) {
247557
+ return rejected19(input.txId, "hyperlink-text-range-unsupported");
247558
+ }
247559
+ const openingEnd = paraXml.indexOf(">", insertion.charStart) + 1;
247560
+ const closingStart = paraXml.lastIndexOf("</", insertion.charEnd);
247561
+ if (openingEnd <= insertion.charStart || closingStart < openingEnd) {
247562
+ return rejected19(input.txId, "hyperlink-tracked-or-comment-unsupported");
247563
+ }
247564
+ const innerXml = paraXml.slice(openingEnd, closingStart);
247565
+ const isolatedInner = isolateSimpleTextRangeInParagraphXml({
247566
+ paragraphXml: `<w:p>${innerXml}</w:p>`,
247567
+ rangeStart: op.on.startOffset - insertion.visibleStart,
247568
+ rangeEnd: op.on.endOffset - insertion.visibleStart,
247569
+ allowDisjointFields: true
247570
+ });
247571
+ if (!isolatedInner.ok)
247572
+ return rejected19(input.txId, mapSimpleTextRangeIsolationReason(isolatedInner.reason));
247573
+ const selectedRuns = isolatedInner.value.selectedRuns.map((run) => renderSimpleTextRunSlice(run, { rPrXml: ensureHyperlinkRunStyle(run, characterStyleId) })).join("");
247574
+ const generatedReplacementXml = isolatedInner.value.beforeRunXml + buildHyperlinkFieldRunsXml({ target: op.target, metadata: op.metadata, resultRunsXml: selectedRuns }) + isolatedInner.value.afterRunXml;
247575
+ const replacementStart = openingEnd + isolatedInner.value.replaceStart - "<w:p>".length;
247576
+ const replacementEnd = openingEnd + isolatedInner.value.replaceEnd - "<w:p>".length;
247577
+ const replacementByteStart = paragraph.byteStart + utf8ByteLength6(paraXml, replacementStart);
247578
+ const replacementXml2 = closeNamespaceScope(generatedReplacementXml, {
247579
+ w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
247580
+ r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
247581
+ }, namespaceBindingsAtPosition(bytes, replacementByteStart), { referencedOnly: true });
247582
+ if (replacementXml2 === null)
247583
+ return rejected19(input.txId, "hyperlink-text-range-unsupported");
247584
+ const documentPatches2 = [{
247585
+ kind: "replaceBytes",
247586
+ order: 0,
247587
+ startByte: replacementByteStart,
247588
+ endByte: paragraph.byteStart + utf8ByteLength6(paraXml, replacementEnd),
247589
+ bytes: TE38.encode(replacementXml2)
247590
+ }];
247591
+ const perPart2 = {
247592
+ [paragraph.partUri]: { kind: "modify", patches: documentPatches2 },
247593
+ ...styleDependencies.value.perPart
247594
+ };
247595
+ return finalize6({
247596
+ input,
247597
+ storyId: op.on.storyId,
247598
+ storyPartUri: paragraph.partUri,
247599
+ sessionEffects: [{ after: compilerHyperlinkCarrier(paragraph.partUri, replacementByteStart, replacementXml2, true) }],
247600
+ perPart: perPart2,
247601
+ preconditions: [
247602
+ buildLocalizedByteWindowPrecondition({ partUri: paragraph.partUri, bytes, patches: documentPatches2 }),
247603
+ ...styleDependencies.value.preconditions
247604
+ ],
247605
+ extraPatchMaps: {},
247606
+ createdRefs: [],
247607
+ updatedRefs: [
247608
+ { kind: "trackedChange", entityId: insertion.rsid, storyId: op.on.storyId },
247609
+ { kind: "block", nodeId: op.on.paraId, storyId: op.on.storyId },
247610
+ { kind: "text", storyId: op.on.storyId, blockId: op.on.paraId, range: { start: op.on.startOffset, end: op.on.endOffset } }
247611
+ ],
247612
+ indexRefreshScope: {
247613
+ perPart: { [paragraph.partUri]: {
247614
+ beforeWindow: { startByte: paragraph.byteStart, endByte: paragraph.byteEnd },
247615
+ kind: "paragraph",
247616
+ blockIds: [op.on.paraId]
247617
+ } }
247618
+ }
247619
+ });
247620
+ }
247420
247621
  const isolated = isolateSimpleTextRangeInParagraphXml({
247421
247622
  paragraphXml: paraXml,
247422
247623
  rangeStart: op.on.startOffset,
@@ -247970,6 +248171,9 @@ function buildHyperlinkRunXml(input) {
247970
248171
  return `<w:hyperlink${attrSegment}>` + runXml + `</w:hyperlink>`;
247971
248172
  }
247972
248173
  function buildTrackedHyperlinkFieldXml(input) {
248174
+ return buildInsOpenTag2(input.stamp) + buildHyperlinkFieldRunsXml(input) + "</w:ins>";
248175
+ }
248176
+ function buildHyperlinkFieldRunsXml(input) {
247973
248177
  const instruction = buildHyperlinkFieldInstruction({
247974
248178
  href: input.target.kind === "external" ? input.target.url : undefined,
247975
248179
  anchor: input.target.kind === "anchor" ? input.target.anchor : undefined,
@@ -247977,7 +248181,7 @@ function buildTrackedHyperlinkFieldXml(input) {
247977
248181
  tooltip: input.metadata?.tooltip,
247978
248182
  targetFrame: input.metadata?.targetFrame
247979
248183
  });
247980
- return buildInsOpenTag2(input.stamp) + '<w:r><w:fldChar w:fldCharType="begin"/></w:r>' + `<w:r><w:instrText>${escapeText(instruction)}</w:instrText></w:r>` + '<w:r><w:fldChar w:fldCharType="separate"/></w:r>' + input.resultRunsXml + '<w:r><w:fldChar w:fldCharType="end"/></w:r>' + "</w:ins>";
248184
+ return '<w:r><w:fldChar w:fldCharType="begin"/></w:r>' + `<w:r><w:instrText>${escapeText(instruction)}</w:instrText></w:r>` + '<w:r><w:fldChar w:fldCharType="separate"/></w:r>' + input.resultRunsXml + '<w:r><w:fldChar w:fldCharType="end"/></w:r>';
247981
248185
  }
247982
248186
  function buildDefaultHyperlinkResultRunXml(text, characterStyleId) {
247983
248187
  return `<w:r><w:rPr><w:rStyle w:val="${escapeAttr7(characterStyleId)}"/></w:rPr><w:t xml:space="preserve">${escapeText(text)}</w:t></w:r>`;
@@ -248120,7 +248324,7 @@ function finalize6(args) {
248120
248324
  backendExtensions: {
248121
248325
  storySurface: {
248122
248326
  family: "storyHyperlink",
248123
- storyLocal: opFromInput.kind === "hyperlinkWrap",
248327
+ storyLocal: opFromInput.kind === "hyperlinkWrap" && Object.keys(args.perPart).every((partUri) => partUri === args.storyPartUri),
248124
248328
  changeMode: opFromInput.kind === "hyperlinkInsert" || opFromInput.kind === "hyperlinkWrap" ? opFromInput.changeMode ?? "direct" : "direct",
248125
248329
  targetBlockIds: args.updatedRefs.flatMap((ref3) => ref3.kind === "block" ? [ref3.nodeId] : []),
248126
248330
  atomCarrierContract: SD_DEFAULT_ATOM_CARRIER_CONTRACT
@@ -248178,8 +248382,10 @@ var init_compile_hyperlink_ops = __esm(() => {
248178
248382
  init_tracked_hyperlink_target();
248179
248383
  init_tracked_hyperlink_removal();
248180
248384
  init_xml_namespace_scope();
248385
+ init_paragraph_inline_model();
248181
248386
  init_paragraph_para_id_attrs();
248182
248387
  init_revision_wid_allocator();
248388
+ init_export_projection();
248183
248389
  init_semantic_style_dependencies();
248184
248390
  init_simple_text_run_split();
248185
248391
  TD71 = new TextDecoder;
@@ -312476,6 +312682,7 @@ function convertHtmlToFragment(html, options = {}) {
312476
312682
  range: { startOffset: 0, endOffset: html.length }
312477
312683
  }), limits.maxDiagnostics);
312478
312684
  }
312685
+ attachSiblingListsToPreviousItems(tree);
312479
312686
  const treeViolation = inspectTreeLimits(tree, limits);
312480
312687
  if (treeViolation) {
312481
312688
  appendBoundedConversionDiagnostic(diagnostics, htmlDiagnostic({
@@ -312537,6 +312744,34 @@ function convertHtmlToFragment(html, options = {}) {
312537
312744
  diagnostics
312538
312745
  };
312539
312746
  }
312747
+ function attachSiblingListsToPreviousItems(parent) {
312748
+ const pending = [parent];
312749
+ while (pending.length > 0) {
312750
+ const current = pending.pop();
312751
+ if ("tagName" in current && (current.tagName === "ul" || current.tagName === "ol")) {
312752
+ let previousItem = null;
312753
+ const retained = [];
312754
+ for (const child of current.childNodes) {
312755
+ if (isElement(child) && child.tagName === "li") {
312756
+ previousItem = child;
312757
+ retained.push(child);
312758
+ } else if (previousItem && isElement(child) && (child.tagName === "ul" || child.tagName === "ol")) {
312759
+ previousItem.childNodes.push(child);
312760
+ child.parentNode = previousItem;
312761
+ } else {
312762
+ if (!isText(child) || child.value.trim() !== "")
312763
+ previousItem = null;
312764
+ retained.push(child);
312765
+ }
312766
+ }
312767
+ current.childNodes = retained;
312768
+ }
312769
+ for (const child of current.childNodes) {
312770
+ if (isElement(child))
312771
+ pending.push(child);
312772
+ }
312773
+ }
312774
+ }
312540
312775
  function parseErrorDiagnostic(error48) {
312541
312776
  return htmlDiagnostic({
312542
312777
  code: "conversion-malformed-input",
@@ -312914,9 +313149,9 @@ function convertSemanticList(root, context, inherited, path6) {
312914
313149
  level,
312915
313150
  path: canonicalPath,
312916
313151
  ...itemValue !== undefined && itemValue !== null ? { marker: `${itemValue}${definition.text?.endsWith(")") ? ")" : "."}` } : {},
312917
- content: content.length > 0 ? content : [
313152
+ content: applyListItemParagraphMarkRunProps(content.length > 0 ? content : [
312918
313153
  paragraph2(context, [], undefined, itemPath, context.droppedContentCount === droppedContentStart)
312919
- ]
313154
+ ], itemContext.runProps)
312920
313155
  });
312921
313156
  for (let nestedIndex = 0;nestedIndex < child.childNodes.length; nestedIndex += 1) {
312922
313157
  const nested = child.childNodes[nestedIndex];
@@ -312984,7 +313219,7 @@ function convertSemanticList(root, context, inherited, path6) {
312984
313219
  level,
312985
313220
  path: canonicalPath,
312986
313221
  ...itemValue !== undefined && itemValue !== null ? { marker: `${itemValue}${definition.text?.endsWith(")") ? ")" : "."}` } : {},
312987
- content: nestedContent
313222
+ content: applyListItemParagraphMarkRunProps(nestedContent, itemContext.runProps)
312988
313223
  });
312989
313224
  }
312990
313225
  if (nestedItems.length === 0)
@@ -313098,7 +313333,7 @@ function convertWordListGroup(group, context, inherited) {
313098
313333
  level: descriptor.level,
313099
313334
  path: canonicalPath,
313100
313335
  ...exceptionalMarker ? { marker: exceptionalMarker } : {},
313101
- content: applyWordListParagraphMarkRunProps(itemContent, itemContext.runProps)
313336
+ content: applyListItemParagraphMarkRunProps(itemContent, itemContext.runProps)
313102
313337
  });
313103
313338
  previousLevel = descriptor.level;
313104
313339
  }
@@ -313110,7 +313345,7 @@ function convertWordListGroup(group, context, inherited) {
313110
313345
  list: { levels: [...levels.values()].sort((a, b) => a.level - b.level), items }
313111
313346
  };
313112
313347
  }
313113
- function applyWordListParagraphMarkRunProps(content, runProps) {
313348
+ function applyListItemParagraphMarkRunProps(content, runProps) {
313114
313349
  if (Object.keys(runProps).length === 0)
313115
313350
  return content;
313116
313351
  let applied = false;
@@ -326322,22 +326557,50 @@ function comparablePlainTokenVariants(plan, plain) {
326322
326557
  return variants;
326323
326558
  }
326324
326559
  function normalizeRepresentedListMarkers(plan, lines) {
326325
- const listTexts = plan.blocks.flatMap((block) => block.kind === "paragraph" && block.listIntent ? [comparableText(blockText(block))] : []);
326326
- if (listTexts.length === 0)
326560
+ const representedTokens = [];
326561
+ const listStarts = new Set;
326562
+ for (const block of plan.blocks) {
326563
+ const tokens = comparableTokens(blockText(block));
326564
+ if (tokens.length > 0 && block.kind === "paragraph" && block.listIntent) {
326565
+ listStarts.add(representedTokens.length);
326566
+ }
326567
+ for (const token of tokens)
326568
+ representedTokens.push(token);
326569
+ }
326570
+ if (listStarts.size === 0)
326327
326571
  return null;
326328
- let listIndex = 0;
326572
+ let tokenIndex = 0;
326573
+ const matchesNext = (tokens) => tokens.length > 0 && tokens.every((token, index2) => token === representedTokens[tokenIndex + index2]);
326329
326574
  let changed = false;
326330
326575
  const normalized = lines.map((line) => {
326331
- if (!hasPlainListMarker(line) || listIndex >= listTexts.length)
326576
+ const tokens = comparableTokens(line);
326577
+ if (matchesNext(tokens)) {
326578
+ tokenIndex += tokens.length;
326332
326579
  return line;
326333
- const withoutMarker = stripPlainListMarker(line);
326334
- if (comparableText(withoutMarker) !== listTexts[listIndex])
326580
+ }
326581
+ if (!listStarts.has(tokenIndex))
326582
+ return line;
326583
+ const withoutMarker = stripRepresentedListMarker(line);
326584
+ if (withoutMarker === null)
326335
326585
  return line;
326336
- listIndex += 1;
326586
+ const withoutMarkerTokens = comparableTokens(withoutMarker);
326587
+ if (!matchesNext(withoutMarkerTokens))
326588
+ return line;
326589
+ tokenIndex += withoutMarkerTokens.length;
326337
326590
  changed = true;
326338
326591
  return withoutMarker;
326339
326592
  });
326340
- return changed && listIndex === listTexts.length ? normalized : null;
326593
+ return changed && tokenIndex === representedTokens.length ? normalized : null;
326594
+ }
326595
+ function stripRepresentedListMarker(line) {
326596
+ if (hasPlainListMarker(line))
326597
+ return stripPlainListMarker(line);
326598
+ const separator = line.indexOf("\t");
326599
+ if (separator < 1)
326600
+ return null;
326601
+ if (!/^(?:o|[\uE000-\uF8FF])$/u.test(line.slice(0, separator).trim()))
326602
+ return null;
326603
+ return line.slice(separator).replace(/^\t+/u, "");
326341
326604
  }
326342
326605
  function hasPlainListMarker(value2) {
326343
326606
  return PLAIN_LIST_MARKER_PATTERN.test(value2);
@@ -326373,7 +326636,7 @@ function isSubsequence(needles, haystack) {
326373
326636
  var PLAIN_LIST_MARKER_PATTERN;
326374
326637
  var init_html_plain_reconciliation = __esm(() => {
326375
326638
  init_contracts();
326376
- PLAIN_LIST_MARKER_PATTERN = /^(?:[•◦▪‣⁃●○■*+-]|\d{1,9}[.)]|[A-Za-z][.)]|[ivxlcdmIVXLCDM]{1,8}[.)])(?:[\t ]+)/u;
326639
+ PLAIN_LIST_MARKER_PATTERN = /^(?:[•◦▪‣⁃●○■□▫◻◽*+-]|\d{1,9}[.)]|[A-Za-z][.)]|[ivxlcdmIVXLCDM]{1,8}[.)])(?:[\t ]+)/u;
326377
326640
  });
326378
326641
 
326379
326642
  // ../../../v2/document-api-v2-adapter/dist/clipboard/parse-v1-slice.js
@@ -328508,15 +328771,14 @@ function* serializeSelectionRangeSteps(context, target, includeHtml, options) {
328508
328771
  let numbering = properties.numbering;
328509
328772
  const listState = readListStateForSession(context.session, resolved.storyId, entry.blockId);
328510
328773
  let listKind = listState?.isListItem ? listState.numFmt === "bullet" ? "bullet" : listState.numFmt ? "ordered" : undefined : undefined;
328774
+ const marker = fullyCovered || listKind ? resolveNumberingLevelForMarker({
328775
+ resolverParams: styleModel.resolverParams,
328776
+ numId: listState?.isListItem && listState.numId != null ? Number(listState.numId) : properties.numbering ? Number(properties.numbering.numId) : undefined,
328777
+ ilvl: listState?.isListItem ? listState.ilvl : properties.numbering ? Number(properties.numbering.ilvl) : undefined,
328778
+ paragraphStyleId: properties.styleRef
328779
+ }) : null;
328511
328780
  if (fullyCovered) {
328512
- const model = copyStyleModel ?? (copyStyleModel = compileCopyStyleModel(context));
328513
- const marker = resolveNumberingLevelForMarker({
328514
- resolverParams: model.resolverParams,
328515
- numId: properties.numbering ? Number(properties.numbering.numId) : undefined,
328516
- ilvl: properties.numbering ? Number(properties.numbering.ilvl) : undefined,
328517
- paragraphStyleId: properties.styleRef
328518
- });
328519
- if (marker.definition && !marker.definition.suppressed) {
328781
+ if (marker?.definition && !marker.definition.suppressed) {
328520
328782
  numbering = {
328521
328783
  numId: String(marker.definition.numId),
328522
328784
  ilvl: String(marker.definition.ilvl)
@@ -328564,7 +328826,8 @@ function* serializeSelectionRangeSteps(context, target, includeHtml, options) {
328564
328826
  ...cellFormatting
328565
328827
  }
328566
328828
  } : {},
328567
- ...listKind ? { listKind } : {},
328829
+ ...listKind ? { listKind, listLevel: listState?.isListItem ? listState.ilvl : listLevel ?? 0 } : {},
328830
+ ...listKind && marker?.definition ? { listMarkerStyle: portableListMarkerStyle(marker.definition, styleModel, paragraphXml) } : {},
328568
328831
  ...semanticHeadingLevel != null && semanticHeadingLevel >= 1 && semanticHeadingLevel <= 6 ? { headingLevel: semanticHeadingLevel } : {},
328569
328832
  parts
328570
328833
  });
@@ -329774,14 +330037,14 @@ function paragraphPaintedLength(xml) {
329774
330037
  const map3 = parseParagraphInlineMap(xml);
329775
330038
  return map3.visibleLength + map3.leaves().filter(isVisibleZeroWidthObjectPiece).length;
329776
330039
  }
329777
- function blockInlineHtml(block, assets) {
329778
- return block.parts.map((part) => renderHtmlPart(part, assets)).join("");
330040
+ function blockInlineHtml(block, assets, defaultTextColor) {
330041
+ return block.parts.map((part) => renderHtmlPart(part, assets, defaultTextColor)).join("");
329779
330042
  }
329780
- function renderHtmlPart(part, assets) {
330043
+ function renderHtmlPart(part, assets, defaultTextColor) {
329781
330044
  if (part.kind === "break")
329782
330045
  return "<br/>";
329783
330046
  if (part.kind === "run")
329784
- return renderHtmlRun(part.run);
330047
+ return renderHtmlRun(part.run, defaultTextColor);
329785
330048
  if (part.kind === "image") {
329786
330049
  const asset = assets.get(part.image.assetId);
329787
330050
  if (!asset)
@@ -329790,18 +330053,17 @@ function renderHtmlPart(part, assets) {
329790
330053
  return `<img src="data:${asset.mimeType};base64,${asset.data}" width="${widthPx}" height="${heightPx}"` + (alt ? ` alt="${escapeHtmlAttribute(alt)}"` : "") + (title2 ? ` title="${escapeHtmlAttribute(title2)}"` : "") + "/>";
329791
330054
  }
329792
330055
  if (part.kind === "sdt")
329793
- return part.parts.map((child) => renderHtmlPart(child, assets)).join("");
330056
+ return part.parts.map((child) => renderHtmlPart(child, assets, defaultTextColor)).join("");
329794
330057
  const href = part.target.kind === "external" ? part.target.url : `#${part.target.anchor}`;
329795
330058
  const title = part.tooltip ? ` title="${escapeHtmlAttribute(part.tooltip)}"` : "";
329796
- return `<a href="${escapeHtmlAttribute(href)}"${title}>${part.parts.map((child) => renderHtmlPart(child, assets)).join("")}</a>`;
330059
+ return `<a href="${escapeHtmlAttribute(href)}"${title}>${part.parts.map((child) => renderHtmlPart(child, assets, defaultTextColor)).join("")}</a>`;
329797
330060
  }
329798
330061
  function buildHtmlFlavor(grouped, assets) {
329799
330062
  const out = [];
329800
- let openList = null;
330063
+ const openLists = [];
329801
330064
  const closeList = () => {
329802
- if (openList) {
329803
- out.push(`</${openList}>`);
329804
- openList = null;
330065
+ while (openLists.length > 0) {
330066
+ out.push(`</li></${openLists.pop().tag}>`);
329805
330067
  }
329806
330068
  };
329807
330069
  for (const entry of grouped) {
@@ -329811,15 +330073,41 @@ function buildHtmlFlavor(grouped, assets) {
329811
330073
  continue;
329812
330074
  }
329813
330075
  const block = entry.block;
329814
- const inline = blockInlineHtml(block, assets);
330076
+ const inline = blockInlineHtml(block, assets, block.listMarkerStyle?.color && block.listMarkerStyle.color !== "000000" ? "000000" : undefined);
329815
330077
  if (block.listKind) {
329816
330078
  const tag = block.listKind === "bullet" ? "ul" : "ol";
329817
- if (openList !== tag) {
329818
- closeList();
329819
- out.push(`<${tag}>`);
329820
- openList = tag;
329821
- }
329822
- out.push(`<li>${inline}</li>`);
330079
+ const styleType = block.listMarkerStyle?.type;
330080
+ const level = block.listLevel ?? 0;
330081
+ if (openLists.length > 0)
330082
+ openLists[0].sourceLevel = Math.min(openLists[0].sourceLevel, level);
330083
+ while (openLists.length > 1 && openLists[openLists.length - 1].sourceLevel > level) {
330084
+ out.push(`</li></${openLists.pop().tag}>`);
330085
+ }
330086
+ const depth = openLists.length === 0 ? 0 : level > openLists[openLists.length - 1].sourceLevel ? openLists.length : openLists.length - 1;
330087
+ if (openLists.length === depth + 1) {
330088
+ out.push("</li>");
330089
+ if (openLists[depth].tag !== tag || openLists[depth].styleType !== styleType) {
330090
+ out.push(`</${openLists.pop().tag}>`);
330091
+ }
330092
+ }
330093
+ if (openLists.length === depth) {
330094
+ const listStyles = [
330095
+ ...styleType ? [`list-style-type: ${styleType}`] : [],
330096
+ ...openLists[depth - 1]?.currentItemHasMarkerColor ? ["color: #000000"] : []
330097
+ ];
330098
+ const orderedType = tag === "ol" ? orderedListTypeAttribute(styleType) : undefined;
330099
+ out.push(`<${tag}${orderedType ? ` type="${orderedType}"` : ""}` + `${listStyles.length > 0 ? ` style="${listStyles.join("; ")}"` : ""}>`);
330100
+ openLists.push({ tag, sourceLevel: level, ...styleType ? { styleType } : {}, currentItemHasMarkerColor: false });
330101
+ }
330102
+ const markerColor = block.listMarkerStyle?.color;
330103
+ const previousItemHadColoredMarker = openLists[openLists.length - 1].currentItemHasMarkerColor;
330104
+ const itemColor = markerColor && markerColor !== "000000" ? markerColor : previousItemHadColoredMarker ? "000000" : undefined;
330105
+ const itemStyles = [
330106
+ ...styleType ? [`list-style-type: ${styleType}`] : [],
330107
+ ...itemColor ? [`color: #${itemColor}`] : []
330108
+ ];
330109
+ out.push(`<li${itemStyles.length > 0 ? ` style="${itemStyles.join("; ")}"` : ""}>${inline}`);
330110
+ openLists[openLists.length - 1].currentItemHasMarkerColor = Boolean(markerColor && markerColor !== "000000");
329823
330111
  continue;
329824
330112
  }
329825
330113
  closeList();
@@ -329831,6 +330119,63 @@ function buildHtmlFlavor(grouped, assets) {
329831
330119
  closeList();
329832
330120
  return out.join("");
329833
330121
  }
330122
+ function portableListMarkerStyle(definition2, model, paragraphXml) {
330123
+ const glyph = definition2.lvlText?.trim();
330124
+ const type = definition2.numFmt === "bullet" ? glyph === "•" || glyph === "●" || glyph === "" ? "disc" : glyph === "◦" || glyph === "○" ? "circle" : glyph === "▪" || glyph === "■" || glyph === "◼" ? "square" : undefined : portableOrderedListStyleType(definition2.numFmt);
330125
+ const runContext = {
330126
+ themeColors: model.themeColors,
330127
+ themeFontScheme: model.themeFontScheme
330128
+ };
330129
+ const directParagraphProperties = parseWordParagraphPropertiesXml(paragraphXml);
330130
+ const resolvedParagraphProperties = model.resolveParagraph({ inlineProps: directParagraphProperties });
330131
+ const markerRun = model.resolveRun({
330132
+ inlineRpr: parseWordRunPropertiesXml(extractParagraphMarkRPrXml(paragraphXml)),
330133
+ resolvedParagraphProperties,
330134
+ isListNumber: true,
330135
+ numberingDefinedInline: directParagraphProperties.numberingProperties != null
330136
+ });
330137
+ const markerColor = normalizeRunAttrsFromOoxml(markerRun, runContext).color;
330138
+ const color2 = markerColor && /^#[0-9a-f]{6}$/i.test(markerColor) ? markerColor.slice(1).toUpperCase() : undefined;
330139
+ return {
330140
+ ...type ? { type } : {},
330141
+ ...color2 ? { color: color2 } : {}
330142
+ };
330143
+ }
330144
+ function portableOrderedListStyleType(numFmt) {
330145
+ switch (numFmt) {
330146
+ case "decimal":
330147
+ return "decimal";
330148
+ case "decimalZero":
330149
+ return "decimal-leading-zero";
330150
+ case "lowerLetter":
330151
+ return "lower-alpha";
330152
+ case "upperLetter":
330153
+ return "upper-alpha";
330154
+ case "lowerRoman":
330155
+ return "lower-roman";
330156
+ case "upperRoman":
330157
+ return "upper-roman";
330158
+ default:
330159
+ return;
330160
+ }
330161
+ }
330162
+ function orderedListTypeAttribute(styleType) {
330163
+ switch (styleType) {
330164
+ case "decimal":
330165
+ case "decimal-leading-zero":
330166
+ return "1";
330167
+ case "lower-alpha":
330168
+ return "a";
330169
+ case "upper-alpha":
330170
+ return "A";
330171
+ case "lower-roman":
330172
+ return "i";
330173
+ case "upper-roman":
330174
+ return "I";
330175
+ default:
330176
+ return;
330177
+ }
330178
+ }
329834
330179
  function tableCellHtmlStyle(cell) {
329835
330180
  const styles = [];
329836
330181
  if (cell.shadingColor)
@@ -329861,14 +330206,15 @@ function tableCellHtmlStyle(cell) {
329861
330206
  }
329862
330207
  return styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
329863
330208
  }
329864
- function renderHtmlRun(run) {
330209
+ function renderHtmlRun(run, defaultTextColor) {
329865
330210
  let html = escapeHtmlText(run.text);
329866
- const marks = run.marks;
329867
- if (!marks)
330211
+ if (!run.marks && !defaultTextColor)
329868
330212
  return html;
330213
+ const marks = run.marks ?? {};
329869
330214
  const styles = [];
329870
- if (marks.color)
329871
- styles.push(`color: #${marks.color}`);
330215
+ const color2 = marks.color ?? defaultTextColor;
330216
+ if (color2)
330217
+ styles.push(`color: #${color2}`);
329872
330218
  if (marks.fontSizePt)
329873
330219
  styles.push(`font-size: ${marks.fontSizePt}pt`);
329874
330220
  if (marks.fontFamily)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdoc/mcp",
3
- "version": "1.7.0-next.12",
3
+ "version": "1.7.0-next.14",
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.20.0-next.12",
27
+ "@superdoc/sdk": "2.20.0-next.14",
28
28
  "debug": "^4.4.3",
29
29
  "zod": "^4.3.6"
30
30
  },
31
31
  "devDependencies": {
32
- "superdoc": "2.23.0-next.12",
33
- "@superdoc/docx-engine": "0.22.0-next.12",
32
+ "superdoc": "2.23.0-next.14",
33
+ "@superdoc/docx-engine": "0.22.0-next.14",
34
34
  "@superdoc/document-api": "0.1.0-alpha.0",
35
35
  "@types/bun": "^1.3.8",
36
36
  "@types/node": "22.19.2",