@beyondwork/docx-react-component 1.0.123 → 1.0.125

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 (101) hide show
  1. package/dist/api/public-types.cjs +147 -35
  2. package/dist/api/public-types.d.cts +2 -2
  3. package/dist/api/public-types.d.ts +2 -2
  4. package/dist/api/public-types.js +3 -3
  5. package/dist/api/v3.cjs +797 -99
  6. package/dist/api/v3.d.cts +3 -3
  7. package/dist/api/v3.d.ts +3 -3
  8. package/dist/api/v3.js +10 -10
  9. package/dist/{canonical-document-CG2TgAzj.d.cts → canonical-document-CXCFCbAz.d.cts} +2 -0
  10. package/dist/{canonical-document-CG2TgAzj.d.ts → canonical-document-CXCFCbAz.d.ts} +2 -0
  11. package/dist/{chunk-PFYUJU3Q.js → chunk-2QL5DAKF.js} +98 -43
  12. package/dist/{chunk-4IPEZYQX.js → chunk-4EENH4FG.js} +1 -1
  13. package/dist/{chunk-BOHHIVQ2.js → chunk-4G3OS2H6.js} +3 -3
  14. package/dist/{chunk-MB7RJBSN.js → chunk-4YJVRIUB.js} +58 -19
  15. package/dist/{chunk-FNWKE74J.js → chunk-5DGKFNQT.js} +5 -1
  16. package/dist/{chunk-RSYN6FTS.js → chunk-6F5QW44A.js} +2 -2
  17. package/dist/{chunk-KOHQFZMM.js → chunk-BYSRJ4FE.js} +1 -1
  18. package/dist/{chunk-H6IL5ABU.js → chunk-CXSYRB37.js} +64 -20
  19. package/dist/{chunk-32ZAOQ54.js → chunk-D5HYZQTG.js} +1 -1
  20. package/dist/{chunk-ML4A4WUN.js → chunk-ESJ2MES5.js} +1 -1
  21. package/dist/{chunk-H2YQKA55.js → chunk-JN444Z5S.js} +505 -44
  22. package/dist/{chunk-IR7QV2BX.js → chunk-KV435YXO.js} +2 -2
  23. package/dist/{chunk-N4VIXI2Z.js → chunk-MWSBGJQO.js} +137 -18
  24. package/dist/{chunk-UHJLCPLU.js → chunk-OHTK7F3F.js} +96 -13
  25. package/dist/{chunk-SGSJ4DQA.js → chunk-QT3LX4FA.js} +321 -51
  26. package/dist/{chunk-NNPVA5VL.js → chunk-TQDQU2E3.js} +2 -2
  27. package/dist/{chunk-E5IBDE5E.js → chunk-V6XVZFFH.js} +2 -2
  28. package/dist/{chunk-RWERZWHR.js → chunk-YD2JE54B.js} +1 -1
  29. package/dist/{chunk-ZRHLLPSJ.js → chunk-YHZHPXDB.js} +85 -18
  30. package/dist/{chunk-HXHQA4BU.js → chunk-YIYM4ZAP.js} +1 -1
  31. package/dist/{chunk-LGWNN3L2.js → chunk-ZDOAUP3V.js} +2 -2
  32. package/dist/compare.d.cts +1 -1
  33. package/dist/compare.d.ts +1 -1
  34. package/dist/core/commands/formatting-commands.d.cts +2 -2
  35. package/dist/core/commands/formatting-commands.d.ts +2 -2
  36. package/dist/core/commands/image-commands.cjs +65 -20
  37. package/dist/core/commands/image-commands.d.cts +2 -2
  38. package/dist/core/commands/image-commands.d.ts +2 -2
  39. package/dist/core/commands/image-commands.js +5 -5
  40. package/dist/core/commands/section-layout-commands.d.cts +2 -2
  41. package/dist/core/commands/section-layout-commands.d.ts +2 -2
  42. package/dist/core/commands/style-commands.d.cts +2 -2
  43. package/dist/core/commands/style-commands.d.ts +2 -2
  44. package/dist/core/commands/table-structure-commands.cjs +65 -20
  45. package/dist/core/commands/table-structure-commands.d.cts +2 -2
  46. package/dist/core/commands/table-structure-commands.d.ts +2 -2
  47. package/dist/core/commands/table-structure-commands.js +4 -4
  48. package/dist/core/commands/text-commands.cjs +66 -21
  49. package/dist/core/commands/text-commands.d.cts +2 -2
  50. package/dist/core/commands/text-commands.d.ts +2 -2
  51. package/dist/core/commands/text-commands.js +5 -5
  52. package/dist/core/selection/mapping.d.cts +2 -2
  53. package/dist/core/selection/mapping.d.ts +2 -2
  54. package/dist/core/state/editor-state.d.cts +2 -2
  55. package/dist/core/state/editor-state.d.ts +2 -2
  56. package/dist/index.cjs +1347 -191
  57. package/dist/index.d.cts +5 -5
  58. package/dist/index.d.ts +5 -5
  59. package/dist/index.js +39 -21
  60. package/dist/io/docx-session.cjs +57 -18
  61. package/dist/io/docx-session.d.cts +4 -4
  62. package/dist/io/docx-session.d.ts +4 -4
  63. package/dist/io/docx-session.js +4 -4
  64. package/dist/legal.cjs +42 -10
  65. package/dist/legal.d.cts +1 -1
  66. package/dist/legal.d.ts +1 -1
  67. package/dist/legal.js +3 -3
  68. package/dist/{loader-D9y4ZRjj.d.ts → loader-B1MxvbeV.d.ts} +3 -3
  69. package/dist/{loader-D9KCtj4m.d.cts → loader-CJXsswcd.d.cts} +3 -3
  70. package/dist/{public-types-DajNGKV4.d.cts → public-types-BEGhv2YR.d.ts} +108 -6
  71. package/dist/{public-types-CNnMHZM9.d.ts → public-types-DrhlQ5Zy.d.cts} +108 -6
  72. package/dist/public-types.cjs +147 -35
  73. package/dist/public-types.d.cts +2 -2
  74. package/dist/public-types.d.ts +2 -2
  75. package/dist/public-types.js +3 -3
  76. package/dist/runtime/collab.d.cts +3 -3
  77. package/dist/runtime/collab.d.ts +3 -3
  78. package/dist/runtime/document-runtime.cjs +685 -98
  79. package/dist/runtime/document-runtime.d.cts +2 -2
  80. package/dist/runtime/document-runtime.d.ts +2 -2
  81. package/dist/runtime/document-runtime.js +14 -14
  82. package/dist/{session-DyQGlryH.d.cts → session-Bp3zqnkS.d.cts} +3 -3
  83. package/dist/{session-DEmaOEjA.d.ts → session-xMOU_NtL.d.ts} +3 -3
  84. package/dist/session.cjs +57 -18
  85. package/dist/session.d.cts +5 -5
  86. package/dist/session.d.ts +5 -5
  87. package/dist/session.js +5 -5
  88. package/dist/tailwind.cjs +238 -73
  89. package/dist/tailwind.d.cts +2 -2
  90. package/dist/tailwind.d.ts +2 -2
  91. package/dist/tailwind.js +7 -7
  92. package/dist/{types-DjJNaE9c.d.ts → types-BFT8536T.d.ts} +2 -2
  93. package/dist/{types-CxE1aZiv.d.cts → types-DDPxEygX.d.cts} +2 -2
  94. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +3 -3
  95. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +3 -3
  96. package/dist/ui-tailwind/editor-surface/search-plugin.js +4 -4
  97. package/dist/ui-tailwind.cjs +238 -73
  98. package/dist/ui-tailwind.d.cts +3 -3
  99. package/dist/ui-tailwind.d.ts +3 -3
  100. package/dist/ui-tailwind.js +7 -7
  101. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -6965,7 +6965,7 @@ function createParagraphEditableTarget(paragraph, kind, storyKey2, blockPath, ta
6965
6965
  context: { storyKey: storyKey2, insideSdt: contentControl !== void 0 },
6966
6966
  ...tableTarget
6967
6967
  }) : void 0;
6968
- const listAddress = tableIdentity === void 0 && paragraph.numbering !== void 0 ? createCanonicalAddress({
6968
+ const listAddress = paragraph.numbering !== void 0 ? createCanonicalAddress({
6969
6969
  addressKind: "list-item-text",
6970
6970
  storyKey: storyKey2,
6971
6971
  staleCheckKind: "paragraph",
@@ -6999,6 +6999,7 @@ function createParagraphEditableTarget(paragraph, kind, storyKey2, blockPath, ta
6999
6999
  ...contentControl !== void 0 ? { contentControl } : {},
7000
7000
  ...tableIdentity !== void 0 ? { table: tableIdentity } : {},
7001
7001
  ...editableOwner !== void 0 ? { editableOwner } : {},
7002
+ ...listAddress !== void 0 ? { listAddress } : {},
7002
7003
  ...tableIdentity !== void 0 ? {
7003
7004
  canonicalAddress: createTableTargetCanonicalAddress(
7004
7005
  tableIdentity,
@@ -7862,6 +7863,9 @@ function validateEditableTargetRef(value, path = "$") {
7862
7863
  if (record.canonicalAddress !== void 0) {
7863
7864
  validateTargetCanonicalAddress(record.canonicalAddress, `${path}.canonicalAddress`, issues);
7864
7865
  }
7866
+ if (record.listAddress !== void 0) {
7867
+ validateTargetCanonicalAddress(record.listAddress, `${path}.listAddress`, issues);
7868
+ }
7865
7869
  const staleCheck = asPlainObject(record.staleCheck, `${path}.staleCheck`, issues);
7866
7870
  if (staleCheck) {
7867
7871
  if (staleCheck.paragraphTextHash !== void 0) {
@@ -9850,6 +9854,7 @@ function mergeLevelDefinition(base, override, startOverride, fallbackLevel) {
9850
9854
  );
9851
9855
  const runProperties = override?.runProperties ?? base?.runProperties;
9852
9856
  const restartAfterLevel = override?.restartAfterLevel ?? base?.restartAfterLevel;
9857
+ const picBulletId = override?.picBulletId ?? base?.picBulletId;
9853
9858
  return {
9854
9859
  level,
9855
9860
  format,
@@ -9860,7 +9865,8 @@ function mergeLevelDefinition(base, override, startOverride, fallbackLevel) {
9860
9865
  ...override?.suffix ?? base?.suffix ? { suffix: override?.suffix ?? base?.suffix } : {},
9861
9866
  ...paragraphGeometry ? { paragraphGeometry } : {},
9862
9867
  ...runProperties ? { runProperties } : {},
9863
- ...restartAfterLevel !== void 0 ? { restartAfterLevel } : {}
9868
+ ...restartAfterLevel !== void 0 ? { restartAfterLevel } : {},
9869
+ ...picBulletId !== void 0 ? { picBulletId } : {}
9864
9870
  };
9865
9871
  }
9866
9872
  function withDefaultStartAt(level) {
@@ -9988,7 +9994,7 @@ function resolveHangingWidth(indentation) {
9988
9994
  // src/runtime/formatting/numbering/prefix.ts
9989
9995
  function createNumberingPrefixResolver(catalog) {
9990
9996
  const sequenceStates = /* @__PURE__ */ new Map();
9991
- function resolveInternal(numbering, paragraph) {
9997
+ function resolveInternal(numbering, paragraph, options = {}) {
9992
9998
  const resolved = resolveNumberingDefinitionSet(
9993
9999
  catalog,
9994
10000
  paragraph?.numbering ?? numbering,
@@ -10001,29 +10007,44 @@ function createNumberingPrefixResolver(catalog) {
10001
10007
  if (!resolvedNumbering) {
10002
10008
  return null;
10003
10009
  }
10004
- const sequenceState = getSequenceState(sequenceStates, resolvedNumbering.numberingInstanceId);
10005
- advanceSequence(sequenceState, resolved.effectiveLevel.level, resolved.effectiveLevels);
10010
+ const advance = options.advance !== false;
10011
+ const sequenceState = getSequenceState(
10012
+ sequenceStates,
10013
+ resolvedNumbering.numberingInstanceId,
10014
+ { create: advance }
10015
+ );
10016
+ if (!sequenceState) {
10017
+ return null;
10018
+ }
10019
+ const workingState = advance ? sequenceState : cloneSequenceState(sequenceState);
10020
+ advanceSequence(workingState, resolved.effectiveLevel.level, resolved.effectiveLevels);
10021
+ const currentCounter = workingState.counters[resolved.effectiveLevel.level];
10006
10022
  const effectiveLevelDefs = resolved.effectiveLevel.isLegalNumbering ? new Map(
10007
10023
  Array.from(resolved.effectiveLevels.entries()).map(([level, definition]) => [
10008
10024
  level,
10009
10025
  { ...definition, format: "decimal" }
10010
10026
  ])
10011
10027
  ) : resolved.effectiveLevels;
10028
+ const picBulletId = resolved.effectiveLevel.picBulletId;
10012
10029
  const text = renderLevelText(
10013
10030
  resolved.effectiveLevel.text,
10014
- sequenceState.counters,
10031
+ workingState.counters,
10015
10032
  effectiveLevelDefs
10016
10033
  );
10017
- if (resolved.effectiveLevel.format !== "none" && text === null) {
10034
+ if (picBulletId == null && resolved.effectiveLevel.format !== "none" && text === null) {
10018
10035
  return null;
10019
10036
  }
10020
10037
  const visibleText = resolved.effectiveLevel.format === "none" ? null : text;
10021
- const picBulletId = resolved.effectiveLevel.picBulletId;
10038
+ const formatPosture = getNumberingFormatPosture(
10039
+ resolved.effectiveLevel.format,
10040
+ currentCounter
10041
+ );
10022
10042
  const picBulletMediaId = picBulletId != null ? catalog.numPicBullets?.[picBulletId]?.mediaId : void 0;
10023
10043
  return {
10024
10044
  text: visibleText,
10025
10045
  level: resolved.effectiveLevel.level,
10026
10046
  format: resolved.effectiveLevel.format,
10047
+ ...formatPosture !== void 0 ? { formatPosture } : {},
10027
10048
  startAt: resolved.effectiveLevel.startAt ?? DEFAULT_NUMBERING_START_AT,
10028
10049
  ...resolved.effectiveLevel.suffix ? { suffix: resolved.effectiveLevel.suffix } : {},
10029
10050
  ...resolved.effectiveLevel.paragraphStyleId ? { paragraphStyleId: resolved.effectiveLevel.paragraphStyleId } : {},
@@ -10034,23 +10055,26 @@ function createNumberingPrefixResolver(catalog) {
10034
10055
  };
10035
10056
  }
10036
10057
  return {
10037
- resolve(numbering) {
10038
- const result = resolveInternal(numbering);
10058
+ resolve(numbering, options) {
10059
+ const result = resolveInternal(numbering, void 0, options);
10039
10060
  return result?.text ?? null;
10040
10061
  },
10041
- resolveDetailed(numbering, paragraph) {
10042
- return resolveInternal(numbering, paragraph);
10062
+ resolveDetailed(numbering, paragraph, options) {
10063
+ return resolveInternal(numbering, paragraph, options);
10043
10064
  },
10044
- resolveParagraph(paragraph) {
10045
- return resolveInternal(paragraph.numbering, paragraph);
10065
+ resolveParagraph(paragraph, options) {
10066
+ return resolveInternal(paragraph.numbering, paragraph, options);
10046
10067
  }
10047
10068
  };
10048
10069
  }
10049
- function getSequenceState(states, numberingInstanceId) {
10070
+ function getSequenceState(states, numberingInstanceId, options = { create: true }) {
10050
10071
  const existing = states.get(numberingInstanceId);
10051
10072
  if (existing) {
10052
10073
  return existing;
10053
10074
  }
10075
+ if (options.create === false) {
10076
+ return { counters: [], lastLevel: null };
10077
+ }
10054
10078
  const created = {
10055
10079
  counters: [],
10056
10080
  lastLevel: null
@@ -10058,6 +10082,12 @@ function getSequenceState(states, numberingInstanceId) {
10058
10082
  states.set(numberingInstanceId, created);
10059
10083
  return created;
10060
10084
  }
10085
+ function cloneSequenceState(state) {
10086
+ return {
10087
+ counters: [...state.counters],
10088
+ lastLevel: state.lastLevel
10089
+ };
10090
+ }
10061
10091
  function advanceSequence(state, currentLevel, levelDefinitions) {
10062
10092
  for (let level = currentLevel + 1; level < state.counters.length; level += 1) {
10063
10093
  if (shouldResetDeeperLevel(level, currentLevel, levelDefinitions)) {
@@ -10089,6 +10119,25 @@ function shouldResetDeeperLevel(level, triggeringLevel, levelDefinitions) {
10089
10119
  function getLevelStartAt(level, levelDefinitions) {
10090
10120
  return levelDefinitions.get(level)?.startAt ?? DEFAULT_NUMBERING_START_AT;
10091
10121
  }
10122
+ function getNumberingFormatPosture(format, value) {
10123
+ if (!isSupportedNumberingFormat(format)) {
10124
+ return {
10125
+ status: "approximated",
10126
+ requestedFormat: format,
10127
+ renderedFormat: "decimal",
10128
+ reason: "unsupported-numbering-format-decimal-fallback"
10129
+ };
10130
+ }
10131
+ if (value !== void 0 && ((format === "upperRoman" || format === "lowerRoman") && (value <= 0 || value >= 4e3) || (format === "cardinalText" || format === "ordinalText") && (!Number.isInteger(value) || value < 1 || value > 999) || (format === "upperLetter" || format === "lowerLetter" || format === "chicago") && value < 1)) {
10132
+ return {
10133
+ status: "approximated",
10134
+ requestedFormat: format,
10135
+ renderedFormat: "decimal",
10136
+ reason: "numbering-format-range-decimal-fallback"
10137
+ };
10138
+ }
10139
+ return void 0;
10140
+ }
10092
10141
  function renderLevelText(text, counters, levelDefinitions) {
10093
10142
  if (!text) {
10094
10143
  return null;
@@ -10931,6 +10980,7 @@ function toNumberingLayoutInput(numbering) {
10931
10980
  associatedTabStops: toLayoutTabStops(numbering.geometry.tabStops, "numbering"),
10932
10981
  level: numbering.level,
10933
10982
  format: numbering.format,
10983
+ ...numbering.formatPosture !== void 0 ? { formatPosture: { ...numbering.formatPosture } } : {},
10934
10984
  startAt: numbering.startAt,
10935
10985
  ...numbering.isLegalNumbering ? { isLegalNumbering: true } : {},
10936
10986
  ...numbering.picBulletMediaId ? { pictureBulletMediaId: numbering.picBulletMediaId } : {}
@@ -11160,13 +11210,10 @@ var FormattingContextImpl = class {
11160
11210
  const effectiveNumbering = this.resolveEffectiveParagraphNumbering(para);
11161
11211
  if (!effectiveNumbering) return null;
11162
11212
  if (!emitGeometry) {
11163
- if (advance) this.numbering.resolve(effectiveNumbering);
11213
+ this.numbering.resolve(effectiveNumbering, { advance });
11164
11214
  return null;
11165
11215
  }
11166
- if (!advance) {
11167
- console.warn("[formatting-context] resolveParagraphNumbering({advance:false}) is not supported; counter always advances");
11168
- }
11169
- return this.numbering.resolveDetailed(effectiveNumbering, para);
11216
+ return this.numbering.resolveDetailed(effectiveNumbering, para, { advance });
11170
11217
  }
11171
11218
  resolveNumberingLayoutInput(para, options = {}) {
11172
11219
  return toNumberingLayoutInput(this.resolveParagraphNumbering(para, options));
@@ -13442,6 +13489,7 @@ function toSurfaceResolvedNumbering(numbering) {
13442
13489
  return {
13443
13490
  level: numbering.level,
13444
13491
  format: numbering.format,
13492
+ ...numbering.formatPosture !== void 0 ? { formatPosture: { ...numbering.formatPosture } } : {},
13445
13493
  ...numbering.text !== null ? { text: numbering.text } : {},
13446
13494
  startAt: numbering.startAt,
13447
13495
  ...numbering.paragraphStyleId ? { paragraphStyleId: numbering.paragraphStyleId } : {},
@@ -18161,8 +18209,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18161
18209
  const perPageCounter = /* @__PURE__ */ new Map();
18162
18210
  const fieldRegionsByParagraphIndex = buildFieldRegionsByParagraphIndex(fieldRegions);
18163
18211
  const generatedTargets = buildGeneratedTargets(editableTargets);
18212
+ const numberingTargets = buildNumberingTargets(editableTargets);
18164
18213
  const bookmarkRanges = buildBookmarkRanges(editableTargets);
18165
- const numberingByParagraphIndex = buildNumberingByParagraphIndex(numberingInputs);
18214
+ const numberingIndex = buildNumberingInputIndex(numberingInputs);
18166
18215
  const pushFragment = (pageIndex, fragment) => {
18167
18216
  const existing = byPage.get(pageIndex);
18168
18217
  if (existing) {
@@ -18198,8 +18247,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18198
18247
  },
18199
18248
  fieldRegionsByParagraphIndex,
18200
18249
  generatedTargets,
18250
+ numberingTargets,
18201
18251
  bookmarkRanges,
18202
- numberingByParagraphIndex,
18252
+ numberingIndex,
18203
18253
  blockPath
18204
18254
  );
18205
18255
  continue;
@@ -18220,8 +18270,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18220
18270
  },
18221
18271
  fieldRegionsByParagraphIndex,
18222
18272
  generatedTargets,
18273
+ numberingTargets,
18223
18274
  bookmarkRanges,
18224
- numberingByParagraphIndex,
18275
+ numberingIndex,
18225
18276
  blockPath
18226
18277
  );
18227
18278
  continue;
@@ -18253,8 +18304,9 @@ function projectSurfaceBlocksToPageFragments(surface, pages, splits, columnByBlo
18253
18304
  paginationRole: "whole",
18254
18305
  fieldRegionsByParagraphIndex,
18255
18306
  generatedTargets,
18307
+ numberingTargets,
18256
18308
  bookmarkRanges,
18257
- numberingByParagraphIndex,
18309
+ numberingIndex,
18258
18310
  blockPath
18259
18311
  }),
18260
18312
  ...columnIndex !== void 0 ? { columnIndex } : {}
@@ -18401,7 +18453,7 @@ function buildRunAnchorsForLine(input) {
18401
18453
  }
18402
18454
  return anchors;
18403
18455
  }
18404
- function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], bookmarkRanges = [], numberingByParagraphIndex = /* @__PURE__ */ new Map(), blockPath) {
18456
+ function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], numberingTargets = [], bookmarkRanges = [], numberingIndex = EMPTY_NUMBERING_INPUT_INDEX, blockPath) {
18405
18457
  for (let i = 0; i < slices.length; i += 1) {
18406
18458
  const slice = slices[i];
18407
18459
  const heightTwips = slice.heightTwips ?? estimateSliceHeightFromLines(slice.lineRange);
@@ -18426,8 +18478,9 @@ function emitSlicedParagraph(block, slices, emit2, fieldRegionsByParagraphIndex
18426
18478
  paginationRole: slice.lineRange.from > 0 ? "continuation" : "slice",
18427
18479
  fieldRegionsByParagraphIndex,
18428
18480
  generatedTargets,
18481
+ numberingTargets,
18429
18482
  bookmarkRanges,
18430
- numberingByParagraphIndex,
18483
+ numberingIndex,
18431
18484
  blockPath
18432
18485
  })
18433
18486
  };
@@ -18448,7 +18501,7 @@ function estimateSliceHeightFromLines(lineRange) {
18448
18501
  const lines = Math.max(0, lineRange.to - lineRange.from);
18449
18502
  return lines * 240;
18450
18503
  }
18451
- function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], bookmarkRanges = [], numberingByParagraphIndex = /* @__PURE__ */ new Map(), blockPath) {
18504
+ function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /* @__PURE__ */ new Map(), generatedTargets = [], numberingTargets = [], bookmarkRanges = [], numberingIndex = EMPTY_NUMBERING_INPUT_INDEX, blockPath) {
18452
18505
  for (let i = 0; i < slices.length; i += 1) {
18453
18506
  const slice = slices[i];
18454
18507
  const heightTwips = slice.heightTwips ?? estimateSliceHeightFromRows(slice.rowRange);
@@ -18472,8 +18525,9 @@ function emitSlicedTable(block, slices, emit2, fieldRegionsByParagraphIndex = /*
18472
18525
  paginationRole: slice.rowRange.from > 0 ? "continuation" : "slice",
18473
18526
  fieldRegionsByParagraphIndex,
18474
18527
  generatedTargets,
18528
+ numberingTargets,
18475
18529
  bookmarkRanges,
18476
- numberingByParagraphIndex,
18530
+ numberingIndex,
18477
18531
  blockPath
18478
18532
  }),
18479
18533
  ...slice.columnIndex !== void 0 ? { columnIndex: slice.columnIndex } : {}
@@ -18547,7 +18601,8 @@ function buildFragmentLayoutObject(input) {
18547
18601
  const numberingRows = collectNumberingLayoutFactsForBlock(
18548
18602
  input.block,
18549
18603
  input.blockPath,
18550
- input.numberingByParagraphIndex
18604
+ input.numberingIndex,
18605
+ input.numberingTargets
18551
18606
  );
18552
18607
  const numbering = input.block.kind === "paragraph" ? numberingRows[0] : void 0;
18553
18608
  const fieldRegions = collectFieldRegionLayoutFacts(
@@ -18718,6 +18773,11 @@ function buildGeneratedTargets(targets) {
18718
18773
  (target) => target.kind === "field-result-text" || target.kind === "hyperlink-text" || target.kind === "hyperlink-destination" || target.kind === "bookmark-anchor" || target.kind === "bookmark-content-range"
18719
18774
  );
18720
18775
  }
18776
+ function buildNumberingTargets(targets) {
18777
+ return targets.filter(
18778
+ (target) => target.listAddress !== void 0 || target.canonicalAddress?.addressKind === "list-item-text"
18779
+ );
18780
+ }
18721
18781
  function buildBookmarkRanges(targets) {
18722
18782
  const anchors = /* @__PURE__ */ new Map();
18723
18783
  const contentRanges = /* @__PURE__ */ new Map();
@@ -18765,14 +18825,27 @@ function buildBookmarkRanges(targets) {
18765
18825
  }
18766
18826
  return ranges;
18767
18827
  }
18768
- function buildNumberingByParagraphIndex(numberingInputs) {
18828
+ var EMPTY_NUMBERING_INPUT_INDEX = {
18829
+ byNumberingKey: /* @__PURE__ */ new Map(),
18830
+ byBlockPath: /* @__PURE__ */ new Map(),
18831
+ byParagraphIndex: /* @__PURE__ */ new Map()
18832
+ };
18833
+ function buildNumberingInputIndex(numberingInputs) {
18834
+ const byNumberingKey = /* @__PURE__ */ new Map();
18835
+ const byBlockPath = /* @__PURE__ */ new Map();
18769
18836
  const byParagraph = /* @__PURE__ */ new Map();
18770
18837
  for (const input of numberingInputs) {
18838
+ if (!byNumberingKey.has(input.numberingKey)) {
18839
+ byNumberingKey.set(input.numberingKey, input);
18840
+ }
18841
+ if (!byBlockPath.has(input.blockPath)) {
18842
+ byBlockPath.set(input.blockPath, input);
18843
+ }
18771
18844
  if (!byParagraph.has(input.paragraphIndex)) {
18772
18845
  byParagraph.set(input.paragraphIndex, input);
18773
18846
  }
18774
18847
  }
18775
- return byParagraph;
18848
+ return { byNumberingKey, byBlockPath, byParagraphIndex: byParagraph };
18776
18849
  }
18777
18850
  function collectBookmarkRangeLayoutFacts(fragmentId, blockPath, bookmarkRanges) {
18778
18851
  if (!blockPath || !bookmarkRanges || bookmarkRanges.length === 0) return [];
@@ -18853,6 +18926,7 @@ function collectNumberingLayoutFacts(block) {
18853
18926
  ...block.numbering?.numberingInstanceId !== void 0 ? { numberingInstanceId: block.numbering.numberingInstanceId } : {},
18854
18927
  ...block.numbering?.level !== void 0 ? { level: block.numbering.level } : {},
18855
18928
  ...block.resolvedNumbering?.format !== void 0 ? { format: block.resolvedNumbering.format } : {},
18929
+ ...block.resolvedNumbering?.formatPosture !== void 0 ? { formatPosture: { ...block.resolvedNumbering.formatPosture } } : {},
18856
18930
  ...block.numberingPrefix !== void 0 ? { markerText: block.numberingPrefix } : {},
18857
18931
  ...block.numberingSuffix !== void 0 ? { markerSuffix: block.numberingSuffix } : {},
18858
18932
  ...block.resolvedNumbering?.geometry.markerJustification !== void 0 ? { markerJustification: block.resolvedNumbering.geometry.markerJustification } : {},
@@ -18880,15 +18954,21 @@ function collectNumberingLayoutFacts(block) {
18880
18954
  } : {}
18881
18955
  };
18882
18956
  }
18883
- function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagraphIndex) {
18957
+ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingIndex, numberingTargets = []) {
18884
18958
  const rows = [];
18885
18959
  const seen = /* @__PURE__ */ new Set();
18886
18960
  visitParagraphBlocks(block, (paragraph, context) => {
18887
18961
  const numbering = collectNumberingLayoutFacts(paragraph);
18888
18962
  if (!numbering) return;
18889
18963
  const paragraphIndex = parseParagraphBlockIndex(paragraph.blockId);
18890
- const canonical = paragraphIndex !== void 0 ? numberingByParagraphIndex?.get(paragraphIndex) : void 0;
18891
18964
  const numberingKey = context.path !== void 0 ? `main:${context.path}:numbering` : void 0;
18965
+ const canonical = lookupNumberingInput(
18966
+ numberingIndex,
18967
+ numberingKey,
18968
+ context.path,
18969
+ paragraphIndex
18970
+ );
18971
+ const target = findNumberingTarget(numberingTargets, context.path);
18892
18972
  const numberingLayoutId = numberingKey ?? [
18893
18973
  "numbering",
18894
18974
  paragraph.blockId,
@@ -18897,6 +18977,7 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18897
18977
  ].join(":");
18898
18978
  if (seen.has(numberingLayoutId)) return;
18899
18979
  seen.add(numberingLayoutId);
18980
+ const unavailableReasons = collectNumberingUnavailableReasons(numbering, canonical);
18900
18981
  rows.push({
18901
18982
  numberingLayoutId,
18902
18983
  ...numberingKey !== void 0 ? { numberingKey } : {},
@@ -18904,6 +18985,10 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18904
18985
  ...canonical?.blockPath !== void 0 ? { sourceBlockPath: canonical.blockPath } : context.path !== void 0 ? { sourceBlockPath: context.path } : {},
18905
18986
  sourceBlockId: paragraph.blockId,
18906
18987
  ...paragraphIndex !== void 0 ? { paragraphIndex } : {},
18988
+ ...target?.targetKey !== void 0 ? { targetKey: target.targetKey } : {},
18989
+ ...target?.kind !== void 0 ? { targetKind: target.kind } : {},
18990
+ ...target?.canonicalAddress?.addressKey !== void 0 ? { canonicalAddressKey: target.canonicalAddress.addressKey } : {},
18991
+ ...target?.listAddress?.addressKey !== void 0 ? { listAddressKey: target.listAddress.addressKey } : {},
18907
18992
  ...canonical?.sourceRef !== void 0 ? { sourceRef: { ...canonical.sourceRef } } : {},
18908
18993
  ...canonical?.numberingSourceRef !== void 0 ? { numberingSourceRef: { ...canonical.numberingSourceRef } } : {},
18909
18994
  ...canonical?.numberingOrigin !== void 0 ? { numberingOrigin: canonical.numberingOrigin } : {},
@@ -18911,11 +18996,41 @@ function collectNumberingLayoutFactsForBlock(block, blockPath, numberingByParagr
18911
18996
  ...canonical?.numberingInstanceSourceRef !== void 0 ? { numberingInstanceSourceRef: { ...canonical.numberingInstanceSourceRef } } : {},
18912
18997
  ...canonical?.abstractNumberingId !== void 0 ? { abstractNumberingId: canonical.abstractNumberingId } : {},
18913
18998
  ...canonical?.abstractNumberingSourceRef !== void 0 ? { abstractNumberingSourceRef: { ...canonical.abstractNumberingSourceRef } } : {},
18914
- ...numbering
18999
+ ...numbering,
19000
+ ...unavailableReasons.length > 0 ? { unavailableReasons } : {}
18915
19001
  });
18916
19002
  }, blockPath);
18917
19003
  return rows;
18918
19004
  }
19005
+ function findNumberingTarget(numberingTargets, blockPath) {
19006
+ if (blockPath === void 0) return void 0;
19007
+ return numberingTargets.find((target) => target.blockPath === blockPath);
19008
+ }
19009
+ function lookupNumberingInput(numberingIndex, numberingKey, blockPath, paragraphIndex) {
19010
+ if (!numberingIndex) return void 0;
19011
+ if (numberingKey !== void 0) {
19012
+ const byKey = numberingIndex.byNumberingKey.get(numberingKey);
19013
+ if (byKey !== void 0) return byKey;
19014
+ }
19015
+ if (blockPath !== void 0) {
19016
+ const byPath = numberingIndex.byBlockPath.get(blockPath);
19017
+ if (byPath !== void 0) return byPath;
19018
+ }
19019
+ return paragraphIndex !== void 0 ? numberingIndex.byParagraphIndex.get(paragraphIndex) : void 0;
19020
+ }
19021
+ function collectNumberingUnavailableReasons(numbering, canonical) {
19022
+ const reasons = [];
19023
+ if (canonical === void 0) {
19024
+ reasons.push("canonical-numbering-input-missing");
19025
+ }
19026
+ if (numbering.markerLane === void 0) {
19027
+ reasons.push("numbering-marker-lane-unavailable");
19028
+ }
19029
+ if (numbering.textColumn === void 0) {
19030
+ reasons.push("numbering-text-column-unavailable");
19031
+ }
19032
+ return reasons;
19033
+ }
18919
19034
  function findPageIndexForOffset(pages, offset) {
18920
19035
  for (let i = 0; i < pages.length; i += 1) {
18921
19036
  const page = pages[i];
@@ -19320,8 +19435,8 @@ async function createCanvasProvider(fontLoader) {
19320
19435
  }
19321
19436
 
19322
19437
  // src/runtime/layout/layout-engine-version.ts
19323
- var LAYOUT_ENGINE_VERSION = 87;
19324
- var LAYCACHE_SCHEMA_VERSION = 11;
19438
+ var LAYOUT_ENGINE_VERSION = 88;
19439
+ var LAYCACHE_SCHEMA_VERSION = 12;
19325
19440
 
19326
19441
  // src/runtime/layout/layout-engine-instance.ts
19327
19442
  var FULL_VIEWPORT_WINDOW_KEY = "full";
@@ -26518,7 +26633,7 @@ function parseCanonicalTextLeafPath(path) {
26518
26633
  if (normalized[offset] !== "/") return null;
26519
26634
  offset += 1;
26520
26635
  }
26521
- return tokens.some((token) => token.kind === "txbx") ? tokens : null;
26636
+ return tokens.length > 0 ? tokens : null;
26522
26637
  }
26523
26638
  function parseCanonicalHyperlinkPath(path) {
26524
26639
  const blockStart = path.indexOf("/block[");
@@ -33493,7 +33608,7 @@ function validateResult(result, context) {
33493
33608
  return { ...result, selection: validated };
33494
33609
  }
33495
33610
  function getPostMutationMaxOffset(result, context) {
33496
- if (typeof context.activeStorySize !== "number" || context.textTarget?.kind === "text-leaf") {
33611
+ if (typeof context.activeStorySize !== "number" || isTargetLocalTextLeaf(context.textTarget)) {
33497
33612
  return result.storyText.length;
33498
33613
  }
33499
33614
  let storySize = context.activeStorySize;
@@ -33502,6 +33617,9 @@ function getPostMutationMaxOffset(result, context) {
33502
33617
  }
33503
33618
  return Math.max(result.storyText.length, storySize);
33504
33619
  }
33620
+ function isTargetLocalTextLeaf(textTarget) {
33621
+ return textTarget?.kind === "text-leaf" && textTarget.blockPath.includes("/txbx/");
33622
+ }
33505
33623
  var editLayer = {
33506
33624
  applyTextInsert(doc, selection, text, context, formatting) {
33507
33625
  return validateResult(insertText(doc, selection, text, context, formatting), context);
@@ -38407,6 +38525,27 @@ function hitTestRegion(index, region, point) {
38407
38525
  (target2) => target2.regionId === region.regionId
38408
38526
  );
38409
38527
  const containing = targets.filter((target2) => containsPoint(target2.rect, point));
38528
+ const generatedTarget = containing.find(
38529
+ (target2) => target2.generatedContentKind === "numbering-marker"
38530
+ );
38531
+ if (generatedTarget) {
38532
+ const anchorHit2 = firstLineAnchor(index, generatedTarget)?.runtimeOffset !== void 0 ? {
38533
+ runtimeOffset: firstLineAnchor(index, generatedTarget).runtimeOffset,
38534
+ assoc: "before"
38535
+ } : resolveLineAnchorHit(index, generatedTarget, point);
38536
+ return {
38537
+ pageIndex: generatedTarget.pageIndex,
38538
+ regionKind: generatedTarget.regionKind,
38539
+ blockId: generatedTarget.blockId,
38540
+ fragmentId: generatedTarget.fragmentId,
38541
+ lineIndex: generatedTarget.lineIndex,
38542
+ runtimeOffset: anchorHit2?.runtimeOffset ?? 0,
38543
+ assoc: "before",
38544
+ generatedContentKind: generatedTarget.generatedContentKind,
38545
+ generatedContentBoundary: generatedTarget.generatedContentBoundary?.policy,
38546
+ semanticEntryId: generatedTarget.targetId.startsWith("hit:") ? generatedTarget.targetId.slice("hit:".length) : generatedTarget.targetId
38547
+ };
38548
+ }
38410
38549
  const target = nearestTarget(containing, point) ?? nearestTarget(targets, point);
38411
38550
  if (!target) return null;
38412
38551
  const anchorHit = resolveLineAnchorHit(index, target, point);
@@ -38783,6 +38922,7 @@ function projectGeometryIndexFromFrame(frame, options) {
38783
38922
  identities,
38784
38923
  storyKey: storyKey2,
38785
38924
  entries: semanticEntries,
38925
+ hitTargets,
38786
38926
  projectedBlocksByStory,
38787
38927
  projectedCommandTargetsByKey,
38788
38928
  precision,
@@ -39053,6 +39193,7 @@ function appendBlockSemanticEntries(input) {
39053
39193
  identities,
39054
39194
  storyKey: storyKey2,
39055
39195
  entries,
39196
+ hitTargets,
39056
39197
  projectedBlocksByStory,
39057
39198
  projectedCommandTargetsByKey,
39058
39199
  precision,
@@ -39082,6 +39223,7 @@ function appendBlockSemanticEntries(input) {
39082
39223
  block,
39083
39224
  sourceIdentity: sliceIdentity,
39084
39225
  entries,
39226
+ hitTargets,
39085
39227
  projectedCommandTargetsByKey,
39086
39228
  precision,
39087
39229
  frameCompleteness,
@@ -39263,6 +39405,7 @@ function appendFragmentLayoutObjectSemanticEntries(input) {
39263
39405
  block,
39264
39406
  sourceIdentity,
39265
39407
  entries,
39408
+ hitTargets,
39266
39409
  projectedCommandTargetsByKey,
39267
39410
  precision,
39268
39411
  frameCompleteness,
@@ -39347,18 +39490,57 @@ function appendFragmentLayoutObjectSemanticEntries(input) {
39347
39490
  }
39348
39491
  return;
39349
39492
  }
39350
- if (layoutObject.kind === "numbered-paragraph") {
39351
- const markerProjection = resolveNumberingMarkerProjection(block);
39493
+ const numberingRows = layoutObject.numberingRows && layoutObject.numberingRows.length > 0 ? layoutObject.numberingRows : layoutObject.kind === "numbered-paragraph" && layoutObject.numbering ? [layoutObject.numbering] : [];
39494
+ for (let index = 0; index < numberingRows.length; index += 1) {
39495
+ const numbering = numberingRows[index];
39496
+ const markerProjection = resolveNumberingMarkerProjection(block, numbering);
39497
+ const entryId = layoutObject.kind === "numbered-paragraph" && index === 0 ? `semantic:numbering-marker:${base.sliceId}` : `semantic:numbering-marker:${base.sliceId}:${stableGeometryId(
39498
+ numbering.numberingLayoutId ?? numbering.numberingKey ?? String(index)
39499
+ )}`;
39500
+ const source = numberingSourceIdentity(numbering, sourceIdentity);
39352
39501
  entries.push({
39353
39502
  ...base,
39354
- entryId: `semantic:numbering-marker:${base.sliceId}`,
39503
+ entryId,
39355
39504
  kind: "numbering-marker",
39356
39505
  layoutObjectId: layoutObject.objectId,
39506
+ numberingLayoutId: numbering.numberingLayoutId,
39507
+ numberingKey: numbering.numberingKey,
39508
+ numberingTargetKey: numbering.targetKey,
39509
+ numberingTargetKind: numbering.targetKind,
39510
+ numberingCanonicalAddressKey: numbering.canonicalAddressKey,
39511
+ numberingListAddressKey: numbering.listAddressKey,
39512
+ numberingMarkerText: numbering.markerText,
39513
+ numberingMarkerSuffix: numbering.markerSuffix,
39514
+ numberingFormat: numbering.format,
39515
+ numberingFormatPosture: numbering.formatPosture,
39516
+ numberingUnavailableReasons: numbering.unavailableReasons,
39517
+ markerGlyphRect: markerProjection.rect,
39518
+ markerLaneRect: markerProjection.markerLaneRect,
39519
+ textColumnRect: markerProjection.textColumnRect,
39520
+ markerBoundary: markerProjection.markerBoundary,
39357
39521
  rect: markerProjection.rect,
39358
39522
  status: markerProjection.status,
39359
39523
  precision: markerProjection.precision,
39360
39524
  frameCompleteness,
39361
- ...sourceIdentity ? { sourceIdentity } : {}
39525
+ ...source ? { sourceIdentity: source } : {}
39526
+ });
39527
+ hitTargets.push({
39528
+ targetId: `hit:${entryId}`,
39529
+ pageId: base.pageId,
39530
+ pageIndex: base.pageIndex,
39531
+ regionId: base.regionId,
39532
+ regionKind: base.regionKind,
39533
+ blockId: base.blockId,
39534
+ fragmentId: base.fragmentId,
39535
+ lineIndex: firstLineIndex(block),
39536
+ rect: markerProjection.rect,
39537
+ precision: markerProjection.precision,
39538
+ generatedContentKind: "numbering-marker",
39539
+ generatedContentBoundary: {
39540
+ policy: "snap-to-authored-text",
39541
+ authoredTextStartsAtPx: markerProjection.markerBoundary.authoredTextStartsAtPx,
39542
+ selectionPolicy: "exclude-generated-marker"
39543
+ }
39362
39544
  });
39363
39545
  recordPrecision(precision, markerProjection.precision);
39364
39546
  }
@@ -39449,8 +39631,8 @@ function bookmarkRangeSourceIdentity(fact, fallback) {
39449
39631
  joinKind: "block-scoped"
39450
39632
  };
39451
39633
  }
39452
- function resolveNumberingMarkerProjection(block) {
39453
- const metadata = resolveNumberingMarkerProjectionMetadata(block);
39634
+ function resolveNumberingMarkerProjection(block, numbering) {
39635
+ const metadata = resolveNumberingMarkerProjectionMetadata(block, numbering);
39454
39636
  const blockFrame = block.frame;
39455
39637
  if (metadata.markerLane && metadata.measuredWidthTwips !== void 0) {
39456
39638
  const markerLane = metadata.markerLane;
@@ -39461,14 +39643,25 @@ function resolveNumberingMarkerProjection(block) {
39461
39643
  const rawRightPx = rawLeftPx + markerLane.widthTwips * pxPerTwip;
39462
39644
  const leftPx = clamp3(rawLeftPx, blockLeftPx, blockRightPx);
39463
39645
  const rightPx = clamp3(rawRightPx, leftPx, blockRightPx);
39646
+ const markerLaneRect = {
39647
+ leftPx,
39648
+ topPx: blockFrame.topPx,
39649
+ widthPx: rightPx - leftPx,
39650
+ heightPx: blockFrame.heightPx,
39651
+ space: "frame",
39652
+ precision: metadata.precision
39653
+ };
39654
+ const textColumnRect = metadata.textColumn ? projectTextColumnRect(blockFrame, metadata.measuredWidthTwips, metadata.textColumn) : void 0;
39464
39655
  return {
39465
- rect: {
39466
- leftPx,
39467
- topPx: blockFrame.topPx,
39468
- widthPx: rightPx - leftPx,
39469
- heightPx: blockFrame.heightPx,
39470
- space: "frame",
39471
- precision: metadata.precision
39656
+ rect: markerLaneRect,
39657
+ markerLaneRect,
39658
+ ...textColumnRect ? { textColumnRect } : {},
39659
+ markerBoundary: {
39660
+ generatedContent: "numbering-marker",
39661
+ caretPolicy: "snap-to-authored-text",
39662
+ selectionPolicy: "exclude-marker-unless-list-item-action",
39663
+ coordinateSpace: "frame-px",
39664
+ ...textColumnRect ? { authoredTextStartsAtPx: textColumnRect.leftPx } : {}
39472
39665
  },
39473
39666
  precision: metadata.precision,
39474
39667
  status: metadata.status
@@ -39487,20 +39680,28 @@ function resolveNumberingMarkerProjection(block) {
39487
39680
  space: "frame",
39488
39681
  precision: metadata.precision
39489
39682
  },
39683
+ markerBoundary: {
39684
+ generatedContent: "numbering-marker",
39685
+ caretPolicy: "snap-to-authored-text",
39686
+ selectionPolicy: "exclude-marker-unless-list-item-action",
39687
+ coordinateSpace: "frame-px"
39688
+ },
39490
39689
  precision: metadata.precision,
39491
39690
  status: metadata.status
39492
39691
  };
39493
39692
  }
39494
- function resolveNumberingMarkerProjectionMetadata(block) {
39693
+ function resolveNumberingMarkerProjectionMetadata(block, numbering) {
39495
39694
  const blockFrame = block.frame;
39496
39695
  const layoutObject = block.fragment.layoutObject;
39497
- const markerLane = layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.markerLane : void 0;
39696
+ const markerLane = numbering?.markerLane ?? (layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.markerLane : void 0);
39697
+ const textColumn = numbering?.textColumn ?? (layoutObject?.kind === "numbered-paragraph" ? layoutObject.numbering?.textColumn : void 0);
39498
39698
  const measuredWidthTwips = layoutObject?.measuredExtentTwips.widthTwips;
39499
39699
  if (markerLane && markerLane.widthTwips > 0 && measuredWidthTwips !== void 0 && measuredWidthTwips > 0 && Number.isFinite(blockFrame.widthPx)) {
39500
39700
  return {
39501
39701
  precision: "within-tolerance",
39502
39702
  status: "realized",
39503
39703
  markerLane,
39704
+ ...textColumn ? { textColumn } : {},
39504
39705
  measuredWidthTwips
39505
39706
  };
39506
39707
  }
@@ -39509,6 +39710,42 @@ function resolveNumberingMarkerProjectionMetadata(block) {
39509
39710
  status: "requires-rehydration"
39510
39711
  };
39511
39712
  }
39713
+ function projectTextColumnRect(blockFrame, measuredWidthTwips, textColumn) {
39714
+ if (measuredWidthTwips <= 0 || !Number.isFinite(blockFrame.widthPx)) {
39715
+ return void 0;
39716
+ }
39717
+ const pxPerTwip = blockFrame.widthPx / measuredWidthTwips;
39718
+ const leftPx = blockFrame.leftPx + textColumn.startTwips * pxPerTwip;
39719
+ const rightInsetPx = (textColumn.rightTwips ?? 0) * pxPerTwip;
39720
+ const rightPx = blockFrame.leftPx + blockFrame.widthPx - rightInsetPx;
39721
+ if (rightPx < leftPx) return void 0;
39722
+ return {
39723
+ leftPx,
39724
+ topPx: blockFrame.topPx,
39725
+ widthPx: rightPx - leftPx,
39726
+ heightPx: blockFrame.heightPx,
39727
+ space: "frame",
39728
+ precision: "within-tolerance"
39729
+ };
39730
+ }
39731
+ function numberingSourceIdentity(numbering, fallback) {
39732
+ const storyKey2 = numbering.storyKey ?? fallback?.storyKey;
39733
+ if (!storyKey2) return fallback;
39734
+ return {
39735
+ storyKey: storyKey2,
39736
+ ...numbering.sourceBlockPath ?? fallback?.blockPath ? { blockPath: numbering.sourceBlockPath ?? fallback?.blockPath } : {},
39737
+ ...numbering.numberingKey ?? fallback?.scopeKey ? { scopeKey: numbering.numberingKey ?? fallback?.scopeKey } : {},
39738
+ ...numbering.numberingInstanceId ?? fallback?.scopeId ? { scopeId: numbering.numberingInstanceId ?? fallback?.scopeId } : {},
39739
+ ...numbering.numberingSourceRef ?? numbering.sourceRef ?? fallback?.sourceRef ? { sourceRef: numbering.numberingSourceRef ?? numbering.sourceRef ?? fallback?.sourceRef } : {},
39740
+ joinKind: "block-scoped"
39741
+ };
39742
+ }
39743
+ function stableGeometryId(value) {
39744
+ return value.replace(/[^A-Za-z0-9_.:-]+/gu, "_");
39745
+ }
39746
+ function firstLineIndex(block) {
39747
+ return block.lines[0]?.line.lineIndex ?? 0;
39748
+ }
39512
39749
  function countBlockSemanticEntries(block) {
39513
39750
  const counts = createPrecisionCounts();
39514
39751
  const layoutObject = block.fragment.layoutObject;
@@ -45908,6 +46145,24 @@ function refusalIdForPostureBlocker(target, blocker2) {
45908
46145
  return "editable_target_opaque_content";
45909
46146
  case "synthetic-layout-cell":
45910
46147
  return "editable_target_synthetic_layout_cell";
46148
+ case "list-text-readback-missing":
46149
+ return "list_text_readback_missing";
46150
+ case "list-structure-command-missing":
46151
+ return "list_structure_command_missing";
46152
+ case "list-target-stale":
46153
+ return "list_target_stale";
46154
+ case "list-secondary-story-unsupported":
46155
+ return "list_secondary_story_unsupported";
46156
+ case "list-table-target-missing":
46157
+ return "list_table_target_missing";
46158
+ case "list-export-persistence-missing":
46159
+ return "list_export_persistence_missing";
46160
+ case "numbering-format-unsupported":
46161
+ return "numbering_format_unsupported";
46162
+ case "picture-bullet-preserve-only":
46163
+ return "picture_bullet_preserve_only";
46164
+ case "marker-geometry-unavailable":
46165
+ return "marker_geometry_unavailable";
45911
46166
  case "unmodeled-target":
45912
46167
  return target.commandFamily === "link-bookmark" ? "editable_target_linked_content_unmodeled" : "editable_target_unmodeled";
45913
46168
  }
@@ -45930,12 +46185,42 @@ function auditCategoryForPostureBlocker(target, blocker2) {
45930
46185
  return target.commandFamily === "link-bookmark" ? "linked-content" : "unsupported-command";
45931
46186
  case "synthetic-layout-cell":
45932
46187
  return "synthetic-cell";
46188
+ case "list-target-stale":
46189
+ return "stale-ref";
46190
+ case "picture-bullet-preserve-only":
46191
+ case "list-export-persistence-missing":
46192
+ return "preserve-only";
46193
+ case "list-text-readback-missing":
46194
+ case "list-structure-command-missing":
46195
+ case "list-secondary-story-unsupported":
46196
+ case "list-table-target-missing":
46197
+ case "numbering-format-unsupported":
46198
+ case "marker-geometry-unavailable":
46199
+ return "unsupported-command";
45933
46200
  }
45934
46201
  }
45935
46202
  function messageForPostureBlocker(blocker2) {
45936
46203
  switch (blocker2) {
45937
46204
  case "synthetic-layout-cell":
45938
46205
  return "Hidden vertical-merge continuation or synthetic layout cells are not editable targets.";
46206
+ case "list-text-readback-missing":
46207
+ return "List text edits need an authoritative list-item text target before mutation.";
46208
+ case "list-structure-command-missing":
46209
+ return "List structure changes need a supported list command envelope before mutation.";
46210
+ case "list-target-stale":
46211
+ return "List target identity is stale for the current canonical document.";
46212
+ case "list-secondary-story-unsupported":
46213
+ return "List edits in this secondary story are not yet supported.";
46214
+ case "list-table-target-missing":
46215
+ return "Table-contained list item is missing a command-safe list target.";
46216
+ case "list-export-persistence-missing":
46217
+ return "List mutation is blocked until export/reopen persistence is available.";
46218
+ case "numbering-format-unsupported":
46219
+ return "Numbering format is unsupported for this list command.";
46220
+ case "picture-bullet-preserve-only":
46221
+ return "Picture bullet lists are preserve-only until picture bullet mutation is supported.";
46222
+ case "marker-geometry-unavailable":
46223
+ return "List marker geometry is unavailable for this target.";
45939
46224
  default:
45940
46225
  return void 0;
45941
46226
  }
@@ -47219,6 +47504,21 @@ function compileParagraphScope(entry, options = {}) {
47219
47504
  partial: true
47220
47505
  };
47221
47506
  }
47507
+ function storyKeyFromHandle(handle) {
47508
+ const target = handle.storyTarget;
47509
+ if (target.kind === "main") return "main";
47510
+ return null;
47511
+ }
47512
+ function textLeafEditableTargetHint(entry, semanticBlockRange) {
47513
+ const storyKey2 = storyKeyFromHandle(entry.handle);
47514
+ if (!storyKey2) return void 0;
47515
+ return {
47516
+ kind: "text-leaf",
47517
+ storyKey: storyKey2,
47518
+ blockPath: `${storyKey2}/block[${entry.blockIndex}]`,
47519
+ semanticBlockRange
47520
+ };
47521
+ }
47222
47522
  function compileParagraphReplacement(entry, proposed, options) {
47223
47523
  if (proposed.operation !== "replace" && proposed.operation !== "insert-before" && proposed.operation !== "insert-after") {
47224
47524
  return null;
@@ -47274,6 +47574,7 @@ function compileParagraphReplacement(entry, proposed, options) {
47274
47574
  {
47275
47575
  kind: stepKind,
47276
47576
  summary: stepKind === "text-replace" ? actionSummary : `suggest-mode ${actionSummary}`,
47577
+ ...textLeafEditableTargetHint(entry, blockRange) ? { editableTargetHint: textLeafEditableTargetHint(entry, blockRange) } : {},
47277
47578
  range: { from: operationRange.from, to: operationRange.to },
47278
47579
  text,
47279
47580
  ...proposed.formatting ? { formatting: proposed.formatting } : {}
@@ -47301,6 +47602,7 @@ function compileParagraphReplacement(entry, proposed, options) {
47301
47602
  {
47302
47603
  kind: "fragment-replace",
47303
47604
  summary: actionSummary,
47605
+ ...textLeafEditableTargetHint(entry, blockRange) ? { editableTargetHint: textLeafEditableTargetHint(entry, blockRange) } : {},
47304
47606
  range: { from: operationRange.from, to: operationRange.to },
47305
47607
  fragment
47306
47608
  }
@@ -49223,14 +49525,17 @@ function paragraphHasBookmarkId(paragraph, bookmarkId) {
49223
49525
  function commandActionHandleForAddress(commandFamily, address) {
49224
49526
  return address ? `scope-command:${commandFamily}:${address.addressKey}` : void 0;
49225
49527
  }
49226
- function withCommandAction(evidence, target) {
49227
- if (evidence.status !== "supported" || !target.canonicalAddress) return evidence;
49528
+ function withCommandAction(evidence, target, canonicalAddress = target.canonicalAddress) {
49529
+ if (evidence.status !== "supported" || !canonicalAddress) return evidence;
49228
49530
  return {
49229
49531
  ...evidence,
49230
- actionHandle: commandActionHandleForAddress(target.commandFamily, target.canonicalAddress),
49231
- canonicalAddress: target.canonicalAddress
49532
+ actionHandle: commandActionHandleForAddress(target.commandFamily, canonicalAddress),
49533
+ canonicalAddress
49232
49534
  };
49233
49535
  }
49536
+ function commandAddressForTarget(target, scopeKind) {
49537
+ return scopeKind === "list-item" && target.listAddress !== void 0 ? target.listAddress : target.canonicalAddress;
49538
+ }
49234
49539
  function runtimeTextCommandEvidence(target, workflowBlockers) {
49235
49540
  const shapeIssues = validateEditableTargetRef(target);
49236
49541
  if (shapeIssues.length > 0) {
@@ -49283,6 +49588,9 @@ var TABLE_TEXT_TARGET_KINDS2 = /* @__PURE__ */ new Set([
49283
49588
  var LIST_TEXT_TARGET_KINDS2 = /* @__PURE__ */ new Set([
49284
49589
  "paragraph-text",
49285
49590
  "sdt-paragraph-text",
49591
+ "table-cell-paragraph-text",
49592
+ "nested-table-cell-paragraph-text",
49593
+ "sdt-table-cell-paragraph-text",
49286
49594
  "secondary-story-paragraph-text"
49287
49595
  ]);
49288
49596
  function tableTextScopeReplacementPosture(target) {
@@ -49333,7 +49641,7 @@ function runtimeCommandEvidence(target, workflowBlockers, textCommand, scopeKind
49333
49641
  intents: commandIntentsForTarget(target, scopeKind),
49334
49642
  reason: textCommand.reason,
49335
49643
  ...textCommand.blockers ? { blockers: textCommand.blockers } : {}
49336
- }, target);
49644
+ }, target, commandAddressForTarget(target, scopeKind));
49337
49645
  }
49338
49646
  if (target.commandFamily === "comment-revision") {
49339
49647
  const isOpen = target.review?.status === "open";
@@ -55385,6 +55693,16 @@ function createLayoutFacet(input) {
55385
55693
  function currentGraph() {
55386
55694
  return engine.getPageGraph(getQueryInput());
55387
55695
  }
55696
+ function fullGraphForViewportIndependentReads() {
55697
+ const query = getQueryInput();
55698
+ if (!query.viewportPageWindow) {
55699
+ return engine.getPageGraph(query);
55700
+ }
55701
+ return engine.getPageGraph({
55702
+ document: query.document,
55703
+ ...query.viewState ? { viewState: query.viewState } : {}
55704
+ });
55705
+ }
55388
55706
  function currentMapper() {
55389
55707
  return engine.getFragmentMapper(getQueryInput());
55390
55708
  }
@@ -55522,7 +55840,7 @@ function createLayoutFacet(input) {
55522
55840
  return graph.sections.map((section) => toPublicSectionNode(graph, section.index)).filter((node) => node !== null);
55523
55841
  },
55524
55842
  getPageForOffset(offset, story) {
55525
- const graph = currentGraph();
55843
+ const graph = fullGraphForViewportIndependentReads();
55526
55844
  const page = findPageForOffsetAndStory(graph, offset, story);
55527
55845
  return page ? toPublicPageNode(page, graph) : null;
55528
55846
  },
@@ -55834,7 +56152,7 @@ function createLayoutFacet(input) {
55834
56152
  return null;
55835
56153
  },
55836
56154
  getBlockHeightsTwips() {
55837
- const graph = currentGraph();
56155
+ const graph = fullGraphForViewportIndependentReads();
55838
56156
  if (blockHeightsCache.revision === graph.revision && blockHeightsCache.map) {
55839
56157
  return blockHeightsCache.map;
55840
56158
  }
@@ -58602,6 +58920,8 @@ async function collectEditorStateForSerialize(args) {
58602
58920
  // src/io/ooxml/parse-bookmark-references.ts
58603
58921
  var HYPERLINK_ANCHOR_RE = /<(?:\w+:)?hyperlink\b[^>]*\bw:anchor\s*=\s*"([^"]*)"/gi;
58604
58922
  var INSTR_TEXT_RE = /<(?:\w+:)?instrText\b[^>]*>([\s\S]*?)<\/(?:\w+:)?instrText>/gi;
58923
+ var FLD_SIMPLE_INSTR_DOUBLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*"([^"]*)"/gi;
58924
+ var FLD_SIMPLE_INSTR_SINGLE_RE = /<(?:\w+:)?fldSimple\b[^>]*?\b(?:w:)?instr\s*=\s*'([^']*)'/gi;
58605
58925
  var TOC_FIELD_RE = /\bTOC\b/;
58606
58926
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
58607
58927
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -58621,12 +58941,21 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58621
58941
  INSTR_TEXT_RE.lastIndex = 0;
58622
58942
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
58623
58943
  const instrText = m[1] ?? "";
58624
- if (TOC_FIELD_RE.test(instrText)) retainAllToc = true;
58625
- REFLIKE_FIELD_RE.lastIndex = 0;
58626
- let r;
58627
- while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
58628
- if (r[1]) retained.add(r[1]);
58629
- }
58944
+ scanFieldInstruction(instrText, retained, () => {
58945
+ retainAllToc = true;
58946
+ });
58947
+ }
58948
+ FLD_SIMPLE_INSTR_DOUBLE_RE.lastIndex = 0;
58949
+ while ((m = FLD_SIMPLE_INSTR_DOUBLE_RE.exec(documentXml)) !== null) {
58950
+ scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
58951
+ retainAllToc = true;
58952
+ });
58953
+ }
58954
+ FLD_SIMPLE_INSTR_SINGLE_RE.lastIndex = 0;
58955
+ while ((m = FLD_SIMPLE_INSTR_SINGLE_RE.exec(documentXml)) !== null) {
58956
+ scanFieldInstruction(decodeXmlAttribute(m[1] ?? ""), retained, () => {
58957
+ retainAllToc = true;
58958
+ });
58630
58959
  }
58631
58960
  retainRevisionBoundedBookmarks(documentXml, retained);
58632
58961
  return {
@@ -58635,6 +58964,17 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58635
58964
  retainAll
58636
58965
  };
58637
58966
  }
58967
+ function scanFieldInstruction(instrText, retained, retainToc) {
58968
+ if (TOC_FIELD_RE.test(instrText)) retainToc();
58969
+ REFLIKE_FIELD_RE.lastIndex = 0;
58970
+ let r;
58971
+ while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
58972
+ if (r[1]) retained.add(r[1]);
58973
+ }
58974
+ }
58975
+ function decodeXmlAttribute(value) {
58976
+ return value.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
58977
+ }
58638
58978
  function retainRevisionBoundedBookmarks(documentXml, retained) {
58639
58979
  const starts = /* @__PURE__ */ new Map();
58640
58980
  BOOKMARK_START_RE.lastIndex = 0;
@@ -58986,18 +59326,23 @@ function parseNumberingXml(xml, context) {
58986
59326
  const abstractDefinitions = {};
58987
59327
  const instances = {};
58988
59328
  const numPicBullets = {};
59329
+ const topLevelOrdinals = /* @__PURE__ */ new Map();
58989
59330
  for (const child of numberingElement.children) {
58990
59331
  if (child.type !== "element") {
58991
59332
  continue;
58992
59333
  }
58993
- if (localName(child.name) === "numPicBullet") {
59334
+ const childName = localName(child.name);
59335
+ const childOrdinal = (topLevelOrdinals.get(childName) ?? 0) + 1;
59336
+ topLevelOrdinals.set(childName, childOrdinal);
59337
+ const childXmlPath = `/numbering[1]/${childName}[${childOrdinal}]`;
59338
+ if (childName === "numPicBullet") {
58994
59339
  const rawId = readStringAttr(child, "w:numPicBulletId");
58995
59340
  if (rawId) {
58996
- numPicBullets[rawId] = readNumPicBullet(child, rawId, context);
59341
+ numPicBullets[rawId] = readNumPicBullet(child, rawId, context, childXmlPath);
58997
59342
  }
58998
59343
  continue;
58999
59344
  }
59000
- switch (localName(child.name)) {
59345
+ switch (childName) {
59001
59346
  case "abstractNum": {
59002
59347
  const rawId = readStringAttr(child, "w:abstractNumId");
59003
59348
  if (!rawId) {
@@ -59017,7 +59362,7 @@ function parseNumberingXml(xml, context) {
59017
59362
  const numStyleLink = numStyleLinkEl ? readStringAttr(numStyleLinkEl, "w:val") : void 0;
59018
59363
  abstractDefinitions[abstractNumberingId] = {
59019
59364
  abstractNumberingId,
59020
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId) } : {},
59365
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId, childXmlPath) } : {},
59021
59366
  levels: readLevels(child),
59022
59367
  ...nsid ? { nsid } : {},
59023
59368
  ...multiLevelType ? { multiLevelType } : {},
@@ -59037,7 +59382,7 @@ function parseNumberingXml(xml, context) {
59037
59382
  const numberingInstanceId = toCanonicalNumberingInstanceId(rawId);
59038
59383
  instances[numberingInstanceId] = {
59039
59384
  numberingInstanceId,
59040
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId) } : {},
59385
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId, childXmlPath) } : {},
59041
59386
  abstractNumberingId: toCanonicalAbstractNumberingId(rawAbstractId),
59042
59387
  overrides: readOverrides(child)
59043
59388
  };
@@ -59051,15 +59396,16 @@ function parseNumberingXml(xml, context) {
59051
59396
  ...Object.keys(numPicBullets).length > 0 ? { numPicBullets } : {}
59052
59397
  };
59053
59398
  }
59054
- function createNumberingSourceRef(partPath, element, rawId) {
59399
+ function createNumberingSourceRef(partPath, element, rawId, xmlPath) {
59055
59400
  return {
59056
59401
  sourceId: `part:${partPath}#${element}:${rawId}`,
59057
59402
  partPath,
59058
59403
  storyKind: "numbering",
59059
- element
59404
+ element,
59405
+ ...xmlPath !== void 0 ? { xmlPath } : {}
59060
59406
  };
59061
59407
  }
59062
- function readNumPicBullet(node, numPicBulletId, context) {
59408
+ function readNumPicBullet(node, numPicBulletId, context, xmlPath) {
59063
59409
  let widthEmu;
59064
59410
  let heightEmu;
59065
59411
  let mediaId;
@@ -59122,6 +59468,7 @@ function readNumPicBullet(node, numPicBulletId, context) {
59122
59468
  }
59123
59469
  return {
59124
59470
  numPicBulletId,
59471
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "numPicBullet", numPicBulletId, xmlPath) } : {},
59125
59472
  rawXml: serializeXmlElementToString(node),
59126
59473
  ...widthEmu !== void 0 ? { widthEmu } : {},
59127
59474
  ...heightEmu !== void 0 ? { heightEmu } : {},
@@ -63088,7 +63435,11 @@ function parseBodyChild(node, sourceXml, relationshipMap, relationships, mediaPa
63088
63435
  switch (localName(child.name)) {
63089
63436
  case "pPr":
63090
63437
  styleId = readParagraphStyleId(child);
63091
- numbering = readParagraphNumbering(child, sourcePartPath);
63438
+ numbering = readParagraphNumbering(
63439
+ child,
63440
+ sourcePartPath,
63441
+ `${sourceXmlPath}/pPr[${countPriorElementSiblingsByName(node, child) + 1}]`
63442
+ );
63092
63443
  alignment = readParagraphAlignment(child);
63093
63444
  spacing = readParagraphSpacing2(child);
63094
63445
  contextualSpacing = readOptionalOnOffParagraphProperty(child, "contextualSpacing");
@@ -64171,7 +64522,7 @@ function readParagraphStyleId(node) {
64171
64522
  }
64172
64523
  return void 0;
64173
64524
  }
64174
- function readParagraphNumbering(node, sourcePartPath) {
64525
+ function readParagraphNumbering(node, sourcePartPath, sourceXmlPath) {
64175
64526
  const numberingProperties = node.children.find(
64176
64527
  (child) => child.type === "element" && localName(child.name) === "numPr"
64177
64528
  );
@@ -64191,16 +64542,22 @@ function readParagraphNumbering(node, sourcePartPath) {
64191
64542
  }
64192
64543
  return {
64193
64544
  numberingInstanceId: toCanonicalNumberingInstanceId(rawInstanceId),
64194
- sourceRef: createElementSourceRef(sourcePartPath, "numPr", numberingProperties),
64545
+ sourceRef: createElementSourceRef(
64546
+ sourcePartPath,
64547
+ "numPr",
64548
+ numberingProperties,
64549
+ sourceXmlPath !== void 0 ? `${sourceXmlPath}/numPr[${countPriorElementSiblingsByName(node, numberingProperties) + 1}]` : void 0
64550
+ ),
64195
64551
  level: Number.parseInt(rawLevel, 10)
64196
64552
  };
64197
64553
  }
64198
- function createElementSourceRef(partPath, element, node) {
64554
+ function createElementSourceRef(partPath, element, node, xmlPath) {
64199
64555
  return {
64200
64556
  sourceId: `part:${partPath}#${element}:${node.start}`,
64201
64557
  partPath,
64202
64558
  storyKind: storyKindFromPartPath(partPath),
64203
64559
  element,
64560
+ ...xmlPath !== void 0 ? { xmlPath } : {},
64204
64561
  startOffset: node.start,
64205
64562
  endOffset: node.end
64206
64563
  };
@@ -66397,19 +66754,19 @@ function locateTargetRange(document2, surface, target) {
66397
66754
  if (!sdt || sdt.kind !== "sdt_block") return null;
66398
66755
  const paragraph = sdt.children[sdtPath.childIndex];
66399
66756
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66400
- return { from: paragraph.from, to: paragraph.to };
66757
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66401
66758
  }
66402
66759
  const paragraphPath = parseTopLevelParagraphPath(target.blockPath);
66403
66760
  if (paragraphPath) {
66404
66761
  const paragraph = surface[paragraphPath.blockIndex];
66405
66762
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66406
- return { from: paragraph.from, to: paragraph.to };
66763
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66407
66764
  }
66408
66765
  const secondaryParagraphPath = parseSecondaryStoryParagraphPath(target.blockPath);
66409
66766
  if (secondaryParagraphPath) {
66410
66767
  const paragraph = surface[secondaryParagraphPath.blockIndex];
66411
66768
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66412
- return { from: paragraph.from, to: paragraph.to };
66769
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66413
66770
  }
66414
66771
  if (target.kind === "textbox-paragraph-text") {
66415
66772
  return {
@@ -66425,6 +66782,18 @@ function locateTargetRange(document2, surface, target) {
66425
66782
  }
66426
66783
  return null;
66427
66784
  }
66785
+ function textLeafTargetRange(target, from, to) {
66786
+ return {
66787
+ from,
66788
+ to,
66789
+ textTarget: {
66790
+ kind: "text-leaf",
66791
+ blockPath: target.blockPath,
66792
+ paragraphStart: from,
66793
+ paragraphEnd: to
66794
+ }
66795
+ };
66796
+ }
66428
66797
  function locateHyperlinkDisplayRange(document2, surface, target) {
66429
66798
  const canonical = resolveHyperlinkDisplayPath(document2, target.blockPath);
66430
66799
  if (!canonical) return null;
@@ -66805,6 +67174,8 @@ function sortJson(value) {
66805
67174
 
66806
67175
  // src/runtime/document-runtime.ts
66807
67176
  var CANONICAL_BLOCK_REFS_SYMBOL2 = /* @__PURE__ */ Symbol.for("wre.canonical-block-refs");
67177
+ var LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES = 5e3;
67178
+ var LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK = 256;
66808
67179
  function getLocalTextPatchMetadata(mapping) {
66809
67180
  const metadata = mapping.metadata?.localTextPatch;
66810
67181
  if (!metadata || typeof metadata !== "object") {
@@ -66977,8 +67348,10 @@ function createDocumentRuntime(options) {
66977
67348
  void upgradeMeasurementProvider(layoutEngine, fontLoader);
66978
67349
  let renderKernelRef = null;
66979
67350
  let runtimeRef = null;
67351
+ const normalizedInitialSurfaceViewportRanges = options.initialSurfaceViewportBlockRanges && options.initialSurfaceViewportBlockRanges.length > 0 ? normalizeViewportRanges(options.initialSurfaceViewportBlockRanges) : null;
67352
+ let initialSurfaceViewportBlockRanges = normalizedInitialSurfaceViewportRanges && normalizedInitialSurfaceViewportRanges.length > 0 ? normalizedInitialSurfaceViewportRanges : null;
66980
67353
  let viewportBlockRanges = null;
66981
- let viewportRangesKey = serializeViewportRanges(null);
67354
+ let viewportRangesKey = serializeViewportRanges(viewportBlockRanges);
66982
67355
  let viewportBlocksPerPageEstimate = null;
66983
67356
  const EDITING_CORRIDOR_BLOCK_RADIUS = 8;
66984
67357
  const getRuntimeForLayoutFacet = () => {
@@ -67218,10 +67591,11 @@ function createDocumentRuntime(options) {
67218
67591
  const cachedContextAnalyticsSnapshots = /* @__PURE__ */ new Map();
67219
67592
  let lastEmittedContextAnalyticsSnapshots;
67220
67593
  function getCachedFullSurface(document2, nextActiveStory) {
67221
- const activeStoryKey = storyTargetKey(nextActiveStory);
67222
- if (cachedFullSurface && cachedFullSurface.content === document2.content && cachedFullSurface.subParts === document2.subParts && cachedFullSurface.styles === document2.styles && cachedFullSurface.numbering === document2.numbering && cachedFullSurface.media === document2.media && cachedFullSurface.preservation === document2.preservation && cachedFullSurface.review === document2.review && cachedFullSurface.effectiveMarkupModeProvider === effectiveMarkupModeProvider && cachedFullSurface.activeStoryKey === activeStoryKey) {
67223
- return cachedFullSurface.snapshot;
67594
+ const cached = getReusableCachedFullSurface(document2, nextActiveStory);
67595
+ if (cached) {
67596
+ return cached;
67224
67597
  }
67598
+ const activeStoryKey = storyTargetKey(nextActiveStory);
67225
67599
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67226
67600
  viewportBlockRanges: null,
67227
67601
  editableTargetsByBlockPath: getEditableTargetsByBlockPath(document2),
@@ -67243,6 +67617,13 @@ function createDocumentRuntime(options) {
67243
67617
  };
67244
67618
  return snapshot;
67245
67619
  }
67620
+ function getReusableCachedFullSurface(document2, nextActiveStory) {
67621
+ const activeStoryKey = storyTargetKey(nextActiveStory);
67622
+ if (cachedFullSurface && cachedFullSurface.content === document2.content && cachedFullSurface.subParts === document2.subParts && cachedFullSurface.styles === document2.styles && cachedFullSurface.numbering === document2.numbering && cachedFullSurface.media === document2.media && cachedFullSurface.preservation === document2.preservation && cachedFullSurface.review === document2.review && cachedFullSurface.effectiveMarkupModeProvider === effectiveMarkupModeProvider && cachedFullSurface.activeStoryKey === activeStoryKey) {
67623
+ return cachedFullSurface.snapshot;
67624
+ }
67625
+ return void 0;
67626
+ }
67246
67627
  function getCachedSurface(document2, nextActiveStory, options2 = {}) {
67247
67628
  const activeStoryKey = storyTargetKey(nextActiveStory);
67248
67629
  const surfaceViewportRanges = "viewportBlockRangesOverride" in options2 ? options2.viewportBlockRangesOverride ?? null : viewportBlockRanges;
@@ -67253,12 +67634,20 @@ function createDocumentRuntime(options) {
67253
67634
  }
67254
67635
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67255
67636
  viewportBlockRanges: surfaceViewportRanges,
67256
- editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPath(document2),
67637
+ editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPathForRanges(
67638
+ document2,
67639
+ activeStoryKey,
67640
+ surfaceViewportRanges
67641
+ ),
67257
67642
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
67258
67643
  });
67259
67644
  recordPerfSample("snapshot.surface");
67260
67645
  incrementInvalidationCounter("runtime.snapshot.surfaceMisses");
67261
- const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(snapshot);
67646
+ const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(
67647
+ snapshot,
67648
+ document2,
67649
+ nextActiveStory
67650
+ );
67262
67651
  if (surfaceViewportRanges === null) {
67263
67652
  cachedFullSurface = {
67264
67653
  content: document2.content,
@@ -67316,7 +67705,7 @@ function createDocumentRuntime(options) {
67316
67705
  }
67317
67706
  return -1;
67318
67707
  }
67319
- function cachePatchedLocalTextSurface(surface) {
67708
+ function cachePatchedLocalTextSurface(surface, fullSurfaceForCache) {
67320
67709
  const activeStoryKey = storyTargetKey(activeStory);
67321
67710
  const rangesKey = serializeViewportRanges(surface.viewportBlockRanges);
67322
67711
  cachedSurface = {
@@ -67332,7 +67721,8 @@ function createDocumentRuntime(options) {
67332
67721
  viewportRangesKey: rangesKey,
67333
67722
  snapshot: surface
67334
67723
  };
67335
- if (surface.viewportBlockRanges === null) {
67724
+ const fullSurface = fullSurfaceForCache ?? (surface.viewportBlockRanges === null ? surface : void 0);
67725
+ if (fullSurface) {
67336
67726
  cachedFullSurface = {
67337
67727
  content: state.document.content,
67338
67728
  subParts: state.document.subParts,
@@ -67343,11 +67733,15 @@ function createDocumentRuntime(options) {
67343
67733
  review: state.document.review,
67344
67734
  effectiveMarkupModeProvider,
67345
67735
  activeStoryKey,
67346
- snapshot: surface
67736
+ snapshot: fullSurface
67347
67737
  };
67348
67738
  }
67349
67739
  cachedSurfaceFingerprint = `${activeStoryKey}|${rangesKey}|${String(state.selection.anchor)}:${String(state.selection.head)}`;
67350
67740
  }
67741
+ function createLocalTextCorridorSurfaceFromFullSurface(fullSurface) {
67742
+ const ranges = getSelectionCorridorViewportRanges(fullSurface);
67743
+ return ranges ? createViewportCulledSurfaceFromFullSurface(fullSurface, ranges) : fullSurface;
67744
+ }
67351
67745
  function tryPatchLocalTextSurface(previousSurface, mapping) {
67352
67746
  const tTotal0 = performance.now();
67353
67747
  try {
@@ -67383,6 +67777,13 @@ function createDocumentRuntime(options) {
67383
67777
  perfCounters.increment("surface.localText.patchMiss");
67384
67778
  return null;
67385
67779
  }
67780
+ const shiftBudget = estimateLocalTextPatchShiftBudget(previousSurface.blocks, blockIndex + 1);
67781
+ perfCounters.increment("surface.localText.shiftedBlocks", shiftBudget.shiftedBlocks);
67782
+ perfCounters.increment("surface.localText.shiftedNodes", shiftBudget.shiftedNodes);
67783
+ if (!shiftBudget.withinBudget) {
67784
+ perfCounters.increment("surface.localText.patchBudgetFallback");
67785
+ return null;
67786
+ }
67386
67787
  const segmentIndex = block.segments.findIndex(
67387
67788
  (segment2) => segment2.kind === "text" && editFrom >= segment2.from && editTo <= segment2.to
67388
67789
  );
@@ -67490,7 +67891,83 @@ function createDocumentRuntime(options) {
67490
67891
  };
67491
67892
  }
67492
67893
  }
67493
- function enrichCulledPlaceholdersWithHeights(snapshot) {
67894
+ function estimateLocalTextPatchShiftBudget(blocks, startIndex) {
67895
+ const shiftedBlocks = Math.max(0, blocks.length - startIndex);
67896
+ let shiftedNodes = 0;
67897
+ for (let index = startIndex; index < blocks.length; index += 1) {
67898
+ const shiftedBlockNodes = countSurfaceShiftNodesUpTo(
67899
+ blocks[index],
67900
+ Math.min(
67901
+ LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK,
67902
+ LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES - shiftedNodes
67903
+ ) + 1
67904
+ );
67905
+ shiftedNodes += shiftedBlockNodes;
67906
+ if (shiftedBlockNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_NODES_PER_BLOCK) {
67907
+ return {
67908
+ shiftedBlocks,
67909
+ shiftedNodes,
67910
+ withinBudget: false
67911
+ };
67912
+ }
67913
+ if (shiftedNodes > LOCAL_TEXT_PATCH_MAX_SHIFTED_SURFACE_NODES) {
67914
+ return {
67915
+ shiftedBlocks,
67916
+ shiftedNodes,
67917
+ withinBudget: false
67918
+ };
67919
+ }
67920
+ }
67921
+ return {
67922
+ shiftedBlocks,
67923
+ shiftedNodes,
67924
+ withinBudget: true
67925
+ };
67926
+ }
67927
+ function countSurfaceShiftNodesUpTo(block, limit) {
67928
+ if (limit <= 0) {
67929
+ return 1;
67930
+ }
67931
+ switch (block.kind) {
67932
+ case "paragraph":
67933
+ return 1 + block.segments.length;
67934
+ case "opaque_block":
67935
+ return 1;
67936
+ case "sdt_block": {
67937
+ let total = 1;
67938
+ for (const child of block.children) {
67939
+ total += countSurfaceShiftNodesUpTo(child, limit - total);
67940
+ if (total > limit) {
67941
+ return total;
67942
+ }
67943
+ }
67944
+ return total;
67945
+ }
67946
+ case "table": {
67947
+ let total = 1;
67948
+ for (const row2 of block.rows) {
67949
+ total += 1;
67950
+ if (total > limit) {
67951
+ return total;
67952
+ }
67953
+ for (const cell of row2.cells) {
67954
+ total += 1;
67955
+ if (total > limit) {
67956
+ return total;
67957
+ }
67958
+ for (const child of cell.content) {
67959
+ total += countSurfaceShiftNodesUpTo(child, limit - total);
67960
+ if (total > limit) {
67961
+ return total;
67962
+ }
67963
+ }
67964
+ }
67965
+ }
67966
+ return total;
67967
+ }
67968
+ }
67969
+ }
67970
+ function enrichCulledPlaceholdersWithHeights(snapshot, document2, nextActiveStory, fullSurfaceForPlaceholders) {
67494
67971
  let heights;
67495
67972
  try {
67496
67973
  heights = layoutFacet.getBlockHeightsTwips();
@@ -67498,17 +67975,19 @@ function createDocumentRuntime(options) {
67498
67975
  return snapshot;
67499
67976
  }
67500
67977
  if (heights.size === 0) return snapshot;
67978
+ const fullSurface = fullSurfaceForPlaceholders ?? getReusableCachedFullSurface(document2, nextActiveStory);
67979
+ if (!fullSurface) return snapshot;
67501
67980
  let changed = false;
67502
67981
  const enrichedBlocks = snapshot.blocks.map((block) => {
67503
67982
  if (block.kind !== "opaque_block" || block.state !== "placeholder-culled") {
67504
67983
  return block;
67505
67984
  }
67506
- const realBlockIdFromOffset = resolveBlockIdFromRuntimeOffset(
67507
- layoutFacet,
67508
- block.from
67985
+ const realBlock = resolveFullSurfaceBlockForPlaceholder(
67986
+ fullSurface,
67987
+ block
67509
67988
  );
67510
- if (!realBlockIdFromOffset) return block;
67511
- const heightTwips = heights.get(realBlockIdFromOffset);
67989
+ if (!realBlock) return block;
67990
+ const heightTwips = heights.get(realBlock.blockId);
67512
67991
  if (typeof heightTwips !== "number" || heightTwips <= 0) return block;
67513
67992
  changed = true;
67514
67993
  return { ...block, placeholderHeightTwips: heightTwips };
@@ -67516,13 +67995,20 @@ function createDocumentRuntime(options) {
67516
67995
  if (!changed) return snapshot;
67517
67996
  return { ...snapshot, blocks: enrichedBlocks };
67518
67997
  }
67519
- function resolveBlockIdFromRuntimeOffset(facet, runtimeOffset) {
67520
- try {
67521
- const frag = facet.getFragmentForOffset?.(runtimeOffset);
67522
- return frag?.blockId ?? null;
67523
- } catch {
67524
- return null;
67998
+ function resolveFullSurfaceBlockForPlaceholder(fullSurface, placeholder) {
67999
+ const index = parsePlaceholderCulledIndex(placeholder.blockId);
68000
+ if (index !== null) {
68001
+ return fullSurface.blocks[index] ?? null;
67525
68002
  }
68003
+ return fullSurface.blocks.find(
68004
+ (block) => block.from === placeholder.from && block.to === placeholder.to
68005
+ ) ?? null;
68006
+ }
68007
+ function parsePlaceholderCulledIndex(blockId) {
68008
+ const match = /^placeholder-culled-(\d+)$/.exec(blockId);
68009
+ if (!match) return null;
68010
+ const index = Number(match[1]);
68011
+ return Number.isSafeInteger(index) ? index : null;
67526
68012
  }
67527
68013
  function getCachedFieldSnapshot(document2) {
67528
68014
  const blockCount = document2.content.children.length;
@@ -68087,7 +68573,14 @@ function createDocumentRuntime(options) {
68087
68573
  revisionToken: state.revisionToken
68088
68574
  });
68089
68575
  perfCounters.increment("refresh.all");
68090
- const surface = timeFacet("surface", () => getCachedSurface(state.document, activeStory));
68576
+ const firstSurfaceViewportBlockRanges = initialSurfaceViewportBlockRanges;
68577
+ initialSurfaceViewportBlockRanges = null;
68578
+ const surface = timeFacet(
68579
+ "surface",
68580
+ () => firstSurfaceViewportBlockRanges ? getCachedSurface(state.document, activeStory, {
68581
+ viewportBlockRangesOverride: firstSurfaceViewportBlockRanges
68582
+ }) : getCachedSurface(state.document, activeStory)
68583
+ );
68091
68584
  const snapshot = {
68092
68585
  documentId: state.documentId,
68093
68586
  sessionId: state.sessionId,
@@ -68185,8 +68678,10 @@ function createDocumentRuntime(options) {
68185
68678
  if (options2.forceProjection) {
68186
68679
  cachedFullSurface = void 0;
68187
68680
  }
68188
- const newSurface = viewportBlockRanges !== null && options2.forceProjection !== true ? createViewportCulledSurfaceFromFullSurface(
68189
- getCachedFullSurface(state.document, activeStory),
68681
+ const reusableFullSurface = viewportBlockRanges !== null && options2.forceProjection !== true ? getReusableCachedFullSurface(state.document, activeStory) : void 0;
68682
+ const derivedFromFull = viewportBlockRanges !== null && reusableFullSurface !== void 0;
68683
+ const projectedSurface = derivedFromFull ? createViewportCulledSurfaceFromFullSurface(
68684
+ reusableFullSurface,
68190
68685
  viewportBlockRanges
68191
68686
  ) : createEditorSurfaceSnapshot(
68192
68687
  state.document,
@@ -68194,11 +68689,21 @@ function createDocumentRuntime(options) {
68194
68689
  activeStory,
68195
68690
  {
68196
68691
  viewportBlockRanges,
68197
- editableTargetsByBlockPath: getEditableTargetsByBlockPath(state.document),
68692
+ editableTargetsByBlockPath: getEditableTargetsByBlockPathForRanges(
68693
+ state.document,
68694
+ activeStoryKey,
68695
+ viewportBlockRanges
68696
+ ),
68198
68697
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
68199
68698
  }
68200
68699
  );
68201
- if (viewportBlockRanges !== null && options2.forceProjection !== true) {
68700
+ const newSurface = viewportBlockRanges !== null ? enrichCulledPlaceholdersWithHeights(
68701
+ projectedSurface,
68702
+ state.document,
68703
+ activeStory,
68704
+ reusableFullSurface
68705
+ ) : projectedSurface;
68706
+ if (derivedFromFull) {
68202
68707
  perfCounters.increment("runtime.viewport.derivedSurfaceRefreshes");
68203
68708
  } else {
68204
68709
  recordPerfSample("snapshot.surface");
@@ -69269,12 +69774,86 @@ function createDocumentRuntime(options) {
69269
69774
  }
69270
69775
  },
69271
69776
  applyScopeReplacement(plan) {
69777
+ const resolveEditableTargetHint = (hint) => {
69778
+ if (!hint) return void 0;
69779
+ const activeStoryKey = storyTargetKey(activeStory);
69780
+ if (hint.storyKey !== activeStoryKey) return null;
69781
+ const currentTargets = collectEditableTargetRefs(
69782
+ state.document,
69783
+ editableTargetBlockCache
69784
+ );
69785
+ const target = currentTargets.find(
69786
+ (target2) => target2.storyKey === hint.storyKey && target2.blockPath === hint.blockPath && target2.commandFamily === "text-leaf"
69787
+ );
69788
+ if (!target) return null;
69789
+ const fallbackTextTarget = {
69790
+ kind: "text-leaf",
69791
+ blockPath: target.blockPath,
69792
+ paragraphStart: hint.semanticBlockRange.from,
69793
+ paragraphEnd: hint.semanticBlockRange.to
69794
+ };
69795
+ const resolved = resolveEditableTextTarget({
69796
+ document: state.document,
69797
+ surface: cachedRenderSnapshot.surface?.blocks ?? [],
69798
+ target,
69799
+ activeStoryKey,
69800
+ editableTargetCache: editableTargetBlockCache
69801
+ });
69802
+ if (resolved.kind === "rejected") {
69803
+ return {
69804
+ textTarget: fallbackTextTarget,
69805
+ range: hint.semanticBlockRange
69806
+ };
69807
+ }
69808
+ return {
69809
+ target,
69810
+ textTarget: resolved.textTarget ?? fallbackTextTarget,
69811
+ range: resolved.range
69812
+ };
69813
+ };
69814
+ const mapSemanticStepRangeToEditableTarget = (stepRange, hint, editableRange) => {
69815
+ if (!hint || !editableRange) return stepRange;
69816
+ const semanticFrom = hint.semanticBlockRange.from;
69817
+ const semanticTo = hint.semanticBlockRange.to;
69818
+ const localFrom = Math.max(0, stepRange.from - semanticFrom);
69819
+ const localTo = Math.max(localFrom, stepRange.to - semanticFrom);
69820
+ const semanticLength = Math.max(0, semanticTo - semanticFrom);
69821
+ const editableLength = Math.max(0, editableRange.to - editableRange.from);
69822
+ if (semanticLength === editableLength) {
69823
+ return {
69824
+ from: editableRange.from + localFrom,
69825
+ to: editableRange.from + localTo
69826
+ };
69827
+ }
69828
+ if (stepRange.from === semanticFrom && stepRange.to === semanticTo) {
69829
+ return editableRange;
69830
+ }
69831
+ return stepRange;
69832
+ };
69272
69833
  for (const step of plan.steps) {
69273
69834
  if (step.kind === "text-replace" && step.range && typeof step.text === "string") {
69835
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
69836
+ if (editableTarget === null) {
69837
+ emit2({
69838
+ type: "command_blocked",
69839
+ documentId: state.documentId,
69840
+ command: "applyScopeReplacement",
69841
+ reasons: [{
69842
+ code: "unsupported_surface",
69843
+ message: "Scope replacement editable target no longer resolves."
69844
+ }]
69845
+ });
69846
+ continue;
69847
+ }
69848
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
69849
+ step.range,
69850
+ step.editableTargetHint,
69851
+ editableTarget?.range
69852
+ );
69274
69853
  const anchor = {
69275
69854
  kind: "range",
69276
- from: step.range.from,
69277
- to: step.range.to,
69855
+ from: dispatchRange.from,
69856
+ to: dispatchRange.to,
69278
69857
  assoc: { start: -1, end: 1 }
69279
69858
  };
69280
69859
  const timestamp = clock();
@@ -69283,6 +69862,8 @@ function createDocumentRuntime(options) {
69283
69862
  {
69284
69863
  type: "text.insert",
69285
69864
  text: step.text,
69865
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69866
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69286
69867
  ...step.formatting ? { formatting: step.formatting } : {},
69287
69868
  origin: createOrigin("api", timestamp)
69288
69869
  },
@@ -69320,10 +69901,28 @@ function createDocumentRuntime(options) {
69320
69901
  emitError(toRuntimeError(error));
69321
69902
  }
69322
69903
  } else if (step.kind === "text-insert-tracked" && step.range && typeof step.text === "string") {
69904
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
69905
+ if (editableTarget === null) {
69906
+ emit2({
69907
+ type: "command_blocked",
69908
+ documentId: state.documentId,
69909
+ command: "applyScopeReplacement",
69910
+ reasons: [{
69911
+ code: "unsupported_surface",
69912
+ message: "Scope replacement editable target no longer resolves."
69913
+ }]
69914
+ });
69915
+ continue;
69916
+ }
69917
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
69918
+ step.range,
69919
+ step.editableTargetHint,
69920
+ editableTarget?.range
69921
+ );
69323
69922
  const anchor = {
69324
69923
  kind: "range",
69325
- from: step.range.from,
69326
- to: step.range.to,
69924
+ from: dispatchRange.from,
69925
+ to: dispatchRange.to,
69327
69926
  assoc: { start: -1, end: 1 }
69328
69927
  };
69329
69928
  const timestamp = clock();
@@ -69332,6 +69931,8 @@ function createDocumentRuntime(options) {
69332
69931
  {
69333
69932
  type: "text.insert",
69334
69933
  text: step.text,
69934
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69935
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69335
69936
  ...step.formatting ? { formatting: step.formatting } : {},
69336
69937
  origin: createOrigin("api", timestamp)
69337
69938
  },
@@ -69346,10 +69947,28 @@ function createDocumentRuntime(options) {
69346
69947
  emitError(toRuntimeError(error));
69347
69948
  }
69348
69949
  } else if (step.kind === "text-delete-tracked" && step.range && step.range.to > step.range.from) {
69950
+ const editableTarget = resolveEditableTargetHint(step.editableTargetHint);
69951
+ if (editableTarget === null) {
69952
+ emit2({
69953
+ type: "command_blocked",
69954
+ documentId: state.documentId,
69955
+ command: "applyScopeReplacement",
69956
+ reasons: [{
69957
+ code: "unsupported_surface",
69958
+ message: "Scope replacement editable target no longer resolves."
69959
+ }]
69960
+ });
69961
+ continue;
69962
+ }
69963
+ const dispatchRange = mapSemanticStepRangeToEditableTarget(
69964
+ step.range,
69965
+ step.editableTargetHint,
69966
+ editableTarget?.range
69967
+ );
69349
69968
  const anchor = {
69350
69969
  kind: "range",
69351
- from: step.range.from,
69352
- to: step.range.to,
69970
+ from: dispatchRange.from,
69971
+ to: dispatchRange.to,
69353
69972
  assoc: { start: -1, end: 1 }
69354
69973
  };
69355
69974
  const timestamp = clock();
@@ -69357,6 +69976,8 @@ function createDocumentRuntime(options) {
69357
69976
  applyTextCommandInActiveStory(
69358
69977
  {
69359
69978
  type: "text.delete-forward",
69979
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69980
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69360
69981
  origin: createOrigin("api", timestamp)
69361
69982
  },
69362
69983
  {
@@ -70877,9 +71498,13 @@ function createDocumentRuntime(options) {
70877
71498
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
70878
71499
  }
70879
71500
  const tValidation0 = performance.now();
70880
- const patchedLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
71501
+ const patchedFullLocalTextSurface = useLocalTextCommitSnapshot ? tryPatchLocalTextSurface(cachedRenderSnapshot.surface, transaction.mapping) : null;
71502
+ const patchedLocalTextSurface = patchedFullLocalTextSurface ? createLocalTextCorridorSurfaceFromFullSurface(patchedFullLocalTextSurface) : null;
70881
71503
  if (patchedLocalTextSurface) {
70882
- cachePatchedLocalTextSurface(patchedLocalTextSurface);
71504
+ cachePatchedLocalTextSurface(
71505
+ patchedLocalTextSurface,
71506
+ patchedFullLocalTextSurface ?? void 0
71507
+ );
70883
71508
  perfCounters.increment("commit.localTextValidation.storySizeOnly");
70884
71509
  }
70885
71510
  const localTextViewportRanges = useLocalTextCommitSnapshot && !patchedLocalTextSurface ? getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface) : void 0;
@@ -70919,7 +71544,8 @@ function createDocumentRuntime(options) {
70919
71544
  cachedRenderSnapshot = useLocalTextCommitSnapshot ? refreshLocalTextCommitSnapshot(surfaceForValidation, transaction.mapping) : refreshRenderSnapshot();
70920
71545
  perfCounters.increment("commit.refresh.us", Math.round((performance.now() - tRefresh0) * 1e3));
70921
71546
  const tNotify0 = performance.now();
70922
- deferNextContextAnalyticsEmit = useLocalTextCommitSnapshot;
71547
+ const shouldDeferContextAnalyticsEmit = transaction.markDirty && transaction.mapping.steps.length > 0;
71548
+ deferNextContextAnalyticsEmit = shouldDeferContextAnalyticsEmit;
70923
71549
  try {
70924
71550
  notify(previous, state, {
70925
71551
  ...transaction,
@@ -89313,6 +89939,12 @@ function openDocxSync(opts) {
89313
89939
  return loadDocxSessionSync(opts);
89314
89940
  }
89315
89941
 
89942
+ // src/api/mounted-surface-residency.ts
89943
+ var MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD = 250;
89944
+ function shouldUseMountedSurfaceViewportCulling(totalBlockCount) {
89945
+ return totalBlockCount > MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD;
89946
+ }
89947
+
89316
89948
  // src/ui/browser-export.ts
89317
89949
  function withExportDelivery(result, delivery) {
89318
89950
  return {
@@ -89883,6 +90515,9 @@ function createRuntime(args, handlers = {}) {
89883
90515
  )
89884
90516
  ));
89885
90517
  const runtimeSessionState = snapshotExportResolution?.barrier ? applySessionExportBarrier(initialSessionState, snapshotExportResolution.barrier) : initialSessionState;
90518
+ const initialSurfaceViewportBlockRanges = getMountedInitialSurfaceViewportBlockRanges(
90519
+ runtimeSessionState
90520
+ );
89886
90521
  const baseRuntime = createDocumentRuntime({
89887
90522
  documentId: args.documentId,
89888
90523
  initialSessionState: runtimeSessionState,
@@ -89894,6 +90529,7 @@ function createRuntime(args, handlers = {}) {
89894
90529
  fatalError: docxSession?.fatalError,
89895
90530
  protectionSnapshot: docxSession?.protectionSnapshot,
89896
90531
  ...args.source.preloadedLaycacheGraph ? { seedLayoutCache: args.source.preloadedLaycacheGraph } : {},
90532
+ ...initialSurfaceViewportBlockRanges ? { initialSurfaceViewportBlockRanges } : {},
89897
90533
  exportDocx: async (sessionState, options) => {
89898
90534
  if (docxSession) {
89899
90535
  return docxSession.exportDocx(sessionState, options);
@@ -89976,6 +90612,18 @@ function createRuntime(args, handlers = {}) {
89976
90612
  });
89977
90613
  return runtime;
89978
90614
  }
90615
+ function getMountedInitialSurfaceViewportBlockRanges(sessionState) {
90616
+ const blockCount = sessionState.canonicalDocument.content.children.length;
90617
+ if (!shouldUseMountedSurfaceViewportCulling(blockCount)) {
90618
+ return void 0;
90619
+ }
90620
+ return Object.freeze([
90621
+ Object.freeze({
90622
+ start: 0,
90623
+ end: MOUNTED_SURFACE_VIEWPORT_BLOCK_THRESHOLD
90624
+ })
90625
+ ]);
90626
+ }
89979
90627
  function createLoadingSnapshot(documentId, readOnly, sourceLabel) {
89980
90628
  return {
89981
90629
  documentId,
@@ -106329,26 +106977,42 @@ function resolveTopBarCommentAvailability(input) {
106329
106977
 
106330
106978
  // src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts
106331
106979
  var import_react39 = require("react");
106332
- function useStatusBarPageFacts(options) {
106333
- const { layoutFacet, selectionPosition, activeStory, renderFrameRevision } = options;
106334
- return (0, import_react39.useMemo)(() => {
106335
- const facet = layoutFacet;
106336
- if (!facet) {
106337
- return {
106338
- displayPageNumber: null,
106339
- pageCount: null,
106340
- measurementFidelity: void 0
106341
- };
106342
- }
106343
- const pageRef = facet.getPageForOffset(selectionPosition, activeStory);
106344
- const displayPageNumber = pageRef !== null && typeof pageRef.pageIndex === "number" ? facet.getDisplayPageNumber(pageRef.pageIndex) ?? pageRef.pageIndex + 1 : null;
106345
- const pageCount = facet.getPageCount();
106980
+ function resolveStatusBarPageFacts(options) {
106981
+ const { layoutFacet: facet, selectionPosition, activeStory, viewportPageIndexRange } = options;
106982
+ if (!facet) {
106346
106983
  return {
106347
- displayPageNumber,
106348
- pageCount,
106349
- measurementFidelity: facet.getMeasurementFidelity()
106984
+ displayPageNumber: null,
106985
+ pageCount: null,
106986
+ measurementFidelity: void 0
106350
106987
  };
106351
- }, [layoutFacet, selectionPosition, activeStory, renderFrameRevision]);
106988
+ }
106989
+ const pageCount = facet.getPageCount();
106990
+ const viewportPageIndex = viewportPageIndexRange && viewportPageIndexRange.start >= 0 && viewportPageIndexRange.start < pageCount ? viewportPageIndexRange.start : null;
106991
+ const pageRef = viewportPageIndex !== null ? { pageIndex: viewportPageIndex } : facet.getPageForOffset(selectionPosition, activeStory);
106992
+ const displayPageNumber = normalizeStatusDisplayPageNumber(
106993
+ pageRef !== null && typeof pageRef.pageIndex === "number" ? facet.getDisplayPageNumber(pageRef.pageIndex) : null,
106994
+ pageRef !== null && typeof pageRef.pageIndex === "number" ? pageRef.pageIndex : null
106995
+ );
106996
+ return {
106997
+ displayPageNumber,
106998
+ pageCount,
106999
+ measurementFidelity: facet.getMeasurementFidelity()
107000
+ };
107001
+ }
107002
+ function normalizeStatusDisplayPageNumber(displayPageNumber, pageIndex) {
107003
+ if (pageIndex === null) return null;
107004
+ return typeof displayPageNumber === "number" && displayPageNumber > 0 ? displayPageNumber : pageIndex + 1;
107005
+ }
107006
+ function useStatusBarPageFacts(options) {
107007
+ const { layoutFacet, selectionPosition, activeStory, renderFrameRevision, viewportPageIndexRange } = options;
107008
+ return (0, import_react39.useMemo)(() => {
107009
+ return resolveStatusBarPageFacts({
107010
+ layoutFacet,
107011
+ selectionPosition,
107012
+ activeStory,
107013
+ viewportPageIndexRange
107014
+ });
107015
+ }, [layoutFacet, selectionPosition, activeStory, viewportPageIndexRange, renderFrameRevision]);
106352
107016
  }
106353
107017
 
106354
107018
  // src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts
@@ -107356,7 +108020,7 @@ function pageMarkersEqual(a, b) {
107356
108020
  }
107357
108021
  return true;
107358
108022
  }
107359
- function useGeometryVisiblePageIndexRange(input) {
108023
+ function useGeometryVisiblePageIndexRanges(input) {
107360
108024
  const {
107361
108025
  scrollRoot,
107362
108026
  geometryFacet,
@@ -107366,10 +108030,12 @@ function useGeometryVisiblePageIndexRange(input) {
107366
108030
  renderFrameRevision,
107367
108031
  viewportScale
107368
108032
  } = input;
107369
- const [range, setRange] = (0, import_react46.useState)(null);
108033
+ const [ranges, setRanges] = (0, import_react46.useState)({ visiblePageIndexRange: null, viewportPageIndexRange: null });
107370
108034
  (0, import_react46.useEffect)(() => {
107371
108035
  if (!scrollRoot || !geometryFacet) {
107372
- setRange((prev) => prev === null ? prev : null);
108036
+ setRanges(
108037
+ (prev) => prev.visiblePageIndexRange === null && prev.viewportPageIndexRange === null ? prev : { visiblePageIndexRange: null, viewportPageIndexRange: null }
108038
+ );
107373
108039
  return void 0;
107374
108040
  }
107375
108041
  const runtime = scrollRoot.ownerDocument?.defaultView;
@@ -107379,7 +108045,7 @@ function useGeometryVisiblePageIndexRange(input) {
107379
108045
  if (disposed) return;
107380
108046
  const pageCount = layoutFacet?.getPageCount() ?? pageMarkerCount;
107381
108047
  const scale = typeof viewportScale === "number" && Number.isFinite(viewportScale) && viewportScale > 0 ? viewportScale : 1;
107382
- const next = resolveVisiblePageIndexRangeFromViewport({
108048
+ const nextVisible = resolveVisiblePageIndexRangeFromViewport({
107383
108049
  pageCount,
107384
108050
  viewportTopPx: scrollRoot.scrollTop / scale,
107385
108051
  viewportHeightPx: scrollRoot.clientHeight / scale,
@@ -107389,7 +108055,22 @@ function useGeometryVisiblePageIndexRange(input) {
107389
108055
  return page ? page.frame : null;
107390
108056
  }
107391
108057
  });
107392
- setRange((prev) => pageRangeEqual(prev, next) ? prev : next);
108058
+ const nextViewport = resolveVisiblePageIndexRangeFromViewport({
108059
+ pageCount,
108060
+ viewportTopPx: scrollRoot.scrollTop / scale,
108061
+ viewportHeightPx: scrollRoot.clientHeight / scale,
108062
+ overscanPages: 0,
108063
+ getPageFrame: (pageIndex) => {
108064
+ const page = geometryFacet.getPage(pageIndex);
108065
+ return page ? page.frame : null;
108066
+ }
108067
+ });
108068
+ setRanges(
108069
+ (prev) => pageRangeEqual(prev.visiblePageIndexRange, nextVisible) && pageRangeEqual(prev.viewportPageIndexRange, nextViewport) ? prev : {
108070
+ visiblePageIndexRange: nextVisible,
108071
+ viewportPageIndexRange: nextViewport
108072
+ }
108073
+ );
107393
108074
  };
107394
108075
  const schedule = () => {
107395
108076
  if (disposed || rafHandle !== null) return;
@@ -107426,7 +108107,7 @@ function useGeometryVisiblePageIndexRange(input) {
107426
108107
  scrollRoot,
107427
108108
  viewportScale
107428
108109
  ]);
107429
- return range;
108110
+ return ranges;
107430
108111
  }
107431
108112
  function shouldUseCompatibilityPageMarkerScan(input) {
107432
108113
  return !input.geometryFacet || !input.layoutFacet;
@@ -107527,7 +108208,11 @@ function usePageMarkers(options) {
107527
108208
  pageMarkers,
107528
108209
  overscanPages
107529
108210
  });
107530
- const geometryVisiblePageIndexRange = useGeometryVisiblePageIndexRange({
108211
+ const markerViewportPageIndexRange = useVisiblePageIndexRange({
108212
+ pageMarkers,
108213
+ overscanPages: 0
108214
+ });
108215
+ const geometryPageIndexRanges = useGeometryVisiblePageIndexRanges({
107531
108216
  scrollRoot: pageStackScrollRoot,
107532
108217
  geometryFacet,
107533
108218
  layoutFacet,
@@ -107536,7 +108221,8 @@ function usePageMarkers(options) {
107536
108221
  renderFrameRevision,
107537
108222
  viewportScale
107538
108223
  });
107539
- const visiblePageIndexRange = geometryVisiblePageIndexRange ?? markerVisiblePageIndexRange;
108224
+ const visiblePageIndexRange = geometryPageIndexRanges.visiblePageIndexRange ?? markerVisiblePageIndexRange;
108225
+ const viewportPageIndexRange = geometryPageIndexRanges.viewportPageIndexRange ?? markerViewportPageIndexRange;
107540
108226
  const visibleBlockRangesFromPageOffsets = (0, import_react46.useMemo)(
107541
108227
  () => visiblePageIndexRange && layoutFacet ? resolveVisibleBlockRangesFromPageOffsets({
107542
108228
  blocks: snapshot.surface?.blocks ?? [],
@@ -107572,9 +108258,11 @@ function usePageMarkers(options) {
107572
108258
  ]
107573
108259
  );
107574
108260
  const visibleBlockRanges = visibleBlockRangesFromPageOffsets ?? visibleBlockRangesFromPageRange ?? markerVisibleBlockRanges;
108261
+ const totalBlockCount = snapshot.surface?.blocks.length ?? 0;
108262
+ const shouldCullSurface = shouldUseMountedSurfaceViewportCulling(totalBlockCount);
107575
108263
  const visibleRangesKey = (0, import_react46.useMemo)(
107576
- () => visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|"),
107577
- [visibleBlockRanges]
108264
+ () => shouldCullSurface ? visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|") : "full",
108265
+ [shouldCullSurface, visibleBlockRanges]
107578
108266
  );
107579
108267
  (0, import_react46.useEffect)(() => {
107580
108268
  if (!layoutFacet) return;
@@ -107583,13 +108271,19 @@ function usePageMarkers(options) {
107583
108271
  layoutFacet.requestViewportRefresh();
107584
108272
  return;
107585
108273
  }
108274
+ if (!shouldCullSurface) {
108275
+ layoutFacet.setVisibleBlockRanges([]);
108276
+ layoutFacet.requestViewportRefresh();
108277
+ return;
108278
+ }
107586
108279
  layoutFacet.setVisibleBlockRanges(visibleBlockRanges);
107587
108280
  layoutFacet.requestViewportRefresh();
107588
- }, [layoutFacet, visibleRangesKey]);
108281
+ }, [layoutFacet, shouldCullSurface, visibleRangesKey]);
107589
108282
  return {
107590
108283
  pageMarkers,
107591
108284
  visibleBlockRanges,
107592
- visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null
108285
+ visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null,
108286
+ viewportPageIndexRange: VIEWPORT_CULLING_ENABLED ? viewportPageIndexRange : null
107593
108287
  };
107594
108288
  }
107595
108289
 
@@ -110016,11 +110710,20 @@ function TwReviewWorkspace(inputProps) {
110016
110710
  selectionToolbarRootRef
110017
110711
  });
110018
110712
  const activePage = props.documentNavigation?.pages[props.documentNavigation.activePageIndex] ?? null;
110713
+ const { visiblePageIndexRange, viewportPageIndexRange } = usePageMarkers({
110714
+ pageStackScrollRoot,
110715
+ snapshot,
110716
+ layoutFacet: props.layoutFacet,
110717
+ geometryFacet: props.geometryFacet,
110718
+ renderFrameRevision,
110719
+ viewportScale: zoomScale
110720
+ });
110019
110721
  const grabbedSegmentOffsets = useGrabbedSegmentOffsets(snapshot);
110020
110722
  const statusBarPageFacts = useStatusBarPageFacts({
110021
110723
  layoutFacet: props.layoutFacet,
110022
110724
  selectionPosition,
110023
110725
  activeStory: snapshot.activeStory,
110726
+ viewportPageIndexRange,
110024
110727
  renderFrameRevision
110025
110728
  });
110026
110729
  const hidePageBorderForActiveEditing = isPageWorkspace && snapshot.activeStory.kind === "main" && shouldHidePageBorderForSelection(viewState.selection);
@@ -110046,14 +110749,6 @@ function TwReviewWorkspace(inputProps) {
110046
110749
  });
110047
110750
  const suppressFloatingToolDuringEditorInput = viewState.editorRole === "editor" && viewState.selection.isCollapsed;
110048
110751
  const shouldRenderFloatingSelectionTool = chromeVisibility.selectionOverlay && gatedSelectionTool && !suppressFloatingToolDuringEditorInput && shouldRenderSelectionToolKind(scopedChromePolicy, gatedSelectionTool.kind);
110049
- const { visiblePageIndexRange } = usePageMarkers({
110050
- pageStackScrollRoot,
110051
- snapshot,
110052
- layoutFacet: props.layoutFacet,
110053
- geometryFacet: props.geometryFacet,
110054
- renderFrameRevision,
110055
- viewportScale: zoomScale
110056
- });
110057
110752
  const { dismissSelectionToolbar, runWithSelectionToolbarDismiss } = useWorkspaceSideEffects({
110058
110753
  layoutFacet: props.layoutFacet,
110059
110754
  activeParagraphLayout,
@@ -127395,6 +128090,17 @@ var hyperlinkDestinationEditMetadata = actionMethodMetadata(
127395
128090
  expectedDelta: "hyperlink destination changes"
127396
128091
  }
127397
128092
  );
128093
+ var hyperlinkTextEditMetadata = actionMethodMetadata(
128094
+ "hyperlinkTextEdit",
128095
+ "mutate",
128096
+ "actions-link-bookmark",
128097
+ "Edit supported hyperlink display text through the L07 text-leaf command target; broad carrier scope rewrite remains refused.",
128098
+ {
128099
+ uiVisible: true,
128100
+ expectsUxResponse: "inline-change",
128101
+ expectedDelta: "hyperlink display text changes"
128102
+ }
128103
+ );
127398
128104
  var listOperationMetadata = actionMethodMetadata(
127399
128105
  "listOperation",
127400
128106
  "mutate",
@@ -127454,6 +128160,7 @@ var ACTION_METHODS = Object.freeze([
127454
128160
  "tocRefresh",
127455
128161
  "bookmarkEdit",
127456
128162
  "hyperlinkDestinationEdit",
128163
+ "hyperlinkTextEdit",
127457
128164
  "listOperation",
127458
128165
  "tableFragment",
127459
128166
  "tableSelection",
@@ -127463,6 +128170,9 @@ var DEFAULT_LOCATE_LIMIT = 20;
127463
128170
  var DEFAULT_REWRITE_ALL_LIMIT = 10;
127464
128171
  var DEFAULT_TABLE_TEXT_SCOPE_LIMIT = 3;
127465
128172
  var DEFAULT_PLAN_STEP_LIMIT = 20;
128173
+ function documentContentHash(runtime) {
128174
+ return JSON.stringify(runtime.getCanonicalDocument().content);
128175
+ }
127466
128176
  function createActionsFamily(runtime) {
127467
128177
  const category = {
127468
128178
  discover(input) {
@@ -127709,6 +128419,14 @@ function createActionsFamily(runtime) {
127709
128419
  ...readback ? { text: readback.text, excerpt: excerpt(readback.text) } : {}
127710
128420
  };
127711
128421
  }
128422
+ if (resolved.target.kind === "editable-text") {
128423
+ return {
128424
+ status: "read",
128425
+ target: summarizeTarget(resolved.target),
128426
+ text: resolved.target.readback.text,
128427
+ excerpt: excerpt(resolved.target.readback.text)
128428
+ };
128429
+ }
127712
128430
  const text = resolved.target.scope.content.text;
127713
128431
  return {
127714
128432
  status: "read",
@@ -127789,6 +128507,31 @@ function createActionsFamily(runtime) {
127789
128507
  input
127790
128508
  );
127791
128509
  },
128510
+ hyperlinkTextEdit(input) {
128511
+ if (input.text === void 0) {
128512
+ return blockedApply(
128513
+ "actions:hyperlink-text-edit:text-required",
128514
+ "input",
128515
+ "Hyperlink display text edit actions require a text value.",
128516
+ "Retry with a text string."
128517
+ );
128518
+ }
128519
+ const resolved = resolveTarget(runtime, input.target);
128520
+ if (!resolved.ok) return blockedApplyFromResolution(resolved);
128521
+ if (resolved.target.kind !== "editable-text" || resolved.target.targetKind !== "hyperlink-text") {
128522
+ return blockedApply(
128523
+ "actions:hyperlink-text-edit:hyperlink-text-handle-required",
128524
+ "unsupported",
128525
+ "Hyperlink display text edits require an exact hyperlink-text actionHandle.",
128526
+ "Call ai.actions.locateAll and retry with a returned scope-command:text-leaf actionHandle."
128527
+ );
128528
+ }
128529
+ return applyEditableTextRewrite(runtime, resolved.target, {
128530
+ text: input.text,
128531
+ actorId: input.actorId,
128532
+ origin: input.origin
128533
+ });
128534
+ },
127792
128535
  listOperation(input) {
127793
128536
  return applyListOperation(runtime, input);
127794
128537
  },
@@ -127837,6 +128580,7 @@ function runPlan(runtime, input) {
127837
128580
  for (const step of input.steps) {
127838
128581
  const result = runPlanStep(runtime, mode, step, input);
127839
128582
  results.push(result);
128583
+ if (isSuspectMutationStep(result)) break;
127840
128584
  if (stopOnBlocker && (result.status === "blocked" || result.status === "unsupported")) {
127841
128585
  break;
127842
128586
  }
@@ -127901,24 +128645,27 @@ function runPlanStep(runtime, mode, step, plan) {
127901
128645
  ...before.readback ? { beforeReadback: before.readback } : {}
127902
128646
  };
127903
128647
  }
128648
+ const documentHashBeforeApply = documentContentHash(runtime);
127904
128649
  const applied = applyPlanStep(runtime, step, plan);
128650
+ const documentHashAfterApply = documentContentHash(runtime);
128651
+ const projectedApply = !applied.applied && documentHashAfterApply !== documentHashBeforeApply ? withSuspectMutationApplyResult(applied, step.id, applied.target ?? before.target) : applied;
127905
128652
  const after = step.kind === "flag" ? before : step.target ? readPlanTarget(runtime, step.target) : before;
127906
128653
  return {
127907
128654
  id: step.id,
127908
128655
  kind: step.kind,
127909
- status: applied.status === "unsupported" ? "unsupported" : applied.applied ? "applied" : "blocked",
127910
- applied: applied.applied,
127911
- changed: applied.changed,
127912
- ...applied.target ?? before.target ? { target: applied.target ?? before.target } : {},
128656
+ status: projectedApply.status === "unsupported" ? "unsupported" : projectedApply.applied ? "applied" : "blocked",
128657
+ applied: projectedApply.applied,
128658
+ changed: projectedApply.changed,
128659
+ ...projectedApply.target ?? before.target ? { target: projectedApply.target ?? before.target } : {},
127913
128660
  ...before.tableAction ? { tableAction: before.tableAction } : {},
127914
128661
  ...before.readback ? { beforeReadback: before.readback } : {},
127915
128662
  ...after.ok && after.readback ? { afterReadback: after.readback } : {},
127916
- ...applied.proposalId ? { proposalId: applied.proposalId } : {},
127917
- ...applied.posture ? { posture: applied.posture } : {},
127918
- ...applied.blockers ? { blockers: applied.blockers } : {},
127919
- ...applied.blockerDetails ? { blockerDetails: applied.blockerDetails } : {},
127920
- ...applied.auditReference ? { auditReference: applied.auditReference } : {},
127921
- ...applied.commandReference ? { commandReference: applied.commandReference } : {}
128663
+ ...projectedApply.proposalId ? { proposalId: projectedApply.proposalId } : {},
128664
+ ...projectedApply.posture ? { posture: projectedApply.posture } : {},
128665
+ ...projectedApply.blockers ? { blockers: projectedApply.blockers } : {},
128666
+ ...projectedApply.blockerDetails ? { blockerDetails: projectedApply.blockerDetails } : {},
128667
+ ...projectedApply.auditReference ? { auditReference: projectedApply.auditReference } : {},
128668
+ ...projectedApply.commandReference ? { commandReference: projectedApply.commandReference } : {}
127922
128669
  };
127923
128670
  }
127924
128671
  function runPlanTableActionStep(runtime, mode, step, plan) {
@@ -128046,6 +128793,23 @@ function locateAll(runtime, input) {
128046
128793
  isEmpty: text.trim().length === 0
128047
128794
  });
128048
128795
  }
128796
+ if (matches.length < limit && !input.kind) {
128797
+ for (const scope of scopes) {
128798
+ if (matches.length >= limit) break;
128799
+ for (const action of editableTextActionsForScope(runtime, scope.handle)) {
128800
+ if (matches.length >= limit) break;
128801
+ if (!textMatches(action.readback.text, input.query, input.matchCase)) continue;
128802
+ matches.push({
128803
+ kind: action.targetKind,
128804
+ text: action.readback.text,
128805
+ excerpt: excerpt(action.readback.text),
128806
+ actionHandle: action.actionHandle,
128807
+ readback: action.readback,
128808
+ isEmpty: action.readback.isEmpty
128809
+ });
128810
+ }
128811
+ }
128812
+ }
128049
128813
  if (matches.length < limit && shouldScanTableText) {
128050
128814
  const tableTextScopeLimit = Math.max(
128051
128815
  0,
@@ -128080,23 +128844,27 @@ function locateAll(runtime, input) {
128080
128844
  function resolveTarget(runtime, target) {
128081
128845
  if ("actionHandle" in target) {
128082
128846
  const action = findTableAction(runtime, target.actionHandle);
128083
- if (!action) {
128084
- return blockedResolution(
128085
- `actions:target:action-handle-not-found:${target.actionHandle}`,
128086
- "unresolved-target",
128087
- "No current table text action matches the supplied actionHandle.",
128088
- "Call ai.actions.locateAll or ai.listTableActions again and retry with a fresh actionHandle."
128089
- );
128847
+ if (action) {
128848
+ if (action.family !== "table-text") {
128849
+ return blockedResolution(
128850
+ `actions:target:action-handle-not-text:${target.actionHandle}`,
128851
+ "unsupported",
128852
+ "This actionHandle is not a table text action.",
128853
+ "Use table structure handles with ai.applyTableAction, or use a table text actionHandle for rewrite."
128854
+ );
128855
+ }
128856
+ return { ok: true, target: { kind: "table-text", action } };
128090
128857
  }
128091
- if (action.family !== "table-text") {
128092
- return blockedResolution(
128093
- `actions:target:action-handle-not-text:${target.actionHandle}`,
128094
- "unsupported",
128095
- "This actionHandle is not a table text action.",
128096
- "Use table structure handles with ai.applyTableAction, or use a table text actionHandle for rewrite."
128097
- );
128858
+ const editableTextAction = findEditableTextAction(runtime, target.actionHandle);
128859
+ if (editableTextAction) {
128860
+ return { ok: true, target: editableTextAction };
128098
128861
  }
128099
- return { ok: true, target: { kind: "table-text", action } };
128862
+ return blockedResolution(
128863
+ `actions:target:action-handle-not-found:${target.actionHandle}`,
128864
+ "unresolved-target",
128865
+ "No current table text or editable text action matches the supplied actionHandle.",
128866
+ "Call ai.actions.locateAll again and retry with a fresh actionHandle."
128867
+ );
128100
128868
  }
128101
128869
  if ("handle" in target) {
128102
128870
  const compiled = createScopeCompilerService(runtime).compileScopeById(target.handle.scopeId);
@@ -128181,7 +128949,21 @@ function applyRewrite(runtime, target, input) {
128181
128949
  ...result2.afterReadback ? { afterReadback: result2.afterReadback } : {}
128182
128950
  };
128183
128951
  }
128952
+ if (target.kind === "editable-text") {
128953
+ return applyEditableTextRewrite(runtime, target, input);
128954
+ }
128955
+ const rewriteBlocker = scopeRewriteCapabilityBlocker(target.scope);
128956
+ if (rewriteBlocker) {
128957
+ return blockedApply(
128958
+ rewriteBlocker.code,
128959
+ rewriteBlocker.category,
128960
+ rewriteBlocker.message,
128961
+ rewriteBlocker.nextStep,
128962
+ [rewriteBlocker]
128963
+ );
128964
+ }
128184
128965
  const beforeText = target.scope.content.text;
128966
+ const documentHashBeforeApply = documentContentHash(runtime);
128185
128967
  const result = createReplacementFamily(runtime).applyReplacementScope({
128186
128968
  targetScopeId: target.handle.scopeId,
128187
128969
  operation: "replace",
@@ -128193,7 +128975,22 @@ function applyRewrite(runtime, target, input) {
128193
128975
  ...input.origin ? { origin: input.origin } : {},
128194
128976
  ...input.proposalId ? { proposalId: input.proposalId } : {}
128195
128977
  });
128196
- return projectRewriteScopeResult(runtime, result, target, beforeText, input.text);
128978
+ const documentMutated = documentContentHash(runtime) !== documentHashBeforeApply;
128979
+ if (!result.applied) {
128980
+ return documentMutated ? withSuspectMutationApplyResult(
128981
+ projectApplyResult(result, target),
128982
+ target.handle.scopeId,
128983
+ summarizeTarget(target)
128984
+ ) : projectApplyResult(result, target);
128985
+ }
128986
+ return projectRewriteScopeResult(
128987
+ runtime,
128988
+ result,
128989
+ target,
128990
+ beforeText,
128991
+ input.text,
128992
+ documentMutated
128993
+ );
128197
128994
  }
128198
128995
  function projectApplyResult(result, target) {
128199
128996
  return {
@@ -128214,7 +129011,79 @@ function projectApplyResult(result, target) {
128214
129011
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128215
129012
  };
128216
129013
  }
128217
- function projectRewriteScopeResult(runtime, result, target, beforeText, proposedText) {
129014
+ function applyEditableTextRewrite(runtime, target, input) {
129015
+ const before = runtime.getCanonicalDocument();
129016
+ runtime.dispatch({
129017
+ type: "selection.set",
129018
+ selection: target.selection,
129019
+ origin: actionOrigin(runtime, input)
129020
+ });
129021
+ runtime.applyActiveStoryTextCommand({
129022
+ type: "text.insert",
129023
+ text: input.text,
129024
+ editableTarget: target.editableTarget,
129025
+ origin: actionOrigin(runtime, input)
129026
+ });
129027
+ const changed = runtime.getCanonicalDocument() !== before;
129028
+ if (!changed) {
129029
+ return blockedApply(
129030
+ `actions:editable-text:runtime-noop:${target.actionHandle}`,
129031
+ "blocked",
129032
+ "The editable text command was accepted but produced no document change.",
129033
+ "Refresh the action handle with ai.actions.locateAll and retry; route persistent failures to L07 text command support.",
129034
+ [
129035
+ blockerWithOwner(
129036
+ `actions:editable-text:runtime-noop:${target.actionHandle}`,
129037
+ "blocked",
129038
+ "The editable text command was accepted but produced no document change.",
129039
+ "Refresh the action handle with ai.actions.locateAll and retry; route persistent failures to L07 text command support.",
129040
+ "L07 runtime text command support"
129041
+ )
129042
+ ]
129043
+ );
129044
+ }
129045
+ const afterTarget = findEditableTextActionByTargetKey(
129046
+ runtime,
129047
+ target.editableTarget.targetKey
129048
+ );
129049
+ const afterReadback = afterTarget?.readback ?? editableTextTargetState(
129050
+ runtime.getCanonicalDocument(),
129051
+ target.editableTarget
129052
+ )?.readback;
129053
+ if (!afterReadback || afterReadback.text !== input.text) {
129054
+ return {
129055
+ status: "blocked",
129056
+ applied: false,
129057
+ changed: true,
129058
+ target: summarizeTarget(afterTarget ?? target),
129059
+ posture: "suspect-readback",
129060
+ blockers: Object.freeze([`actions:editable-text:readback-mismatch:${target.actionHandle}`]),
129061
+ blockerDetails: Object.freeze([
129062
+ blocker(
129063
+ `actions:editable-text:readback-mismatch:${target.actionHandle}`,
129064
+ "blocked",
129065
+ "The editable text command changed the document, but exact target readback did not match the proposed text.",
129066
+ "Treat the mutation as suspect. Re-read the target and export before claiming success."
129067
+ )
129068
+ ]),
129069
+ ...afterReadback ? { afterReadback } : {}
129070
+ };
129071
+ }
129072
+ return {
129073
+ status: "applied",
129074
+ applied: true,
129075
+ changed: true,
129076
+ target: summarizeTarget(afterTarget ?? { ...target, readback: afterReadback }),
129077
+ commandReference: {
129078
+ command: "text.insert",
129079
+ actorId: input.actorId ?? "v3-ai-api",
129080
+ origin: input.origin ?? "agent",
129081
+ emittedAtUtc: currentAuditTimestamp(runtime)
129082
+ },
129083
+ afterReadback
129084
+ };
129085
+ }
129086
+ function projectRewriteScopeResult(runtime, result, target, beforeText, proposedText, documentMutated) {
128218
129087
  if (!result.applied) return projectApplyResult(result, target);
128219
129088
  const compiledAfter = createScopeCompilerService(runtime).compileScopeById(
128220
129089
  target.handle.scopeId
@@ -128225,7 +129094,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128225
129094
  target,
128226
129095
  `actions:rewrite:authoritative-readback-unresolvable:${target.handle.scopeId}`,
128227
129096
  "The replacement primitive reported success, but the target scope could not be re-read afterwards.",
128228
- "Treat the mutation as untrusted. Re-locate the target and retry only after the scope resolves, or create an issue flag instead."
129097
+ "Treat the mutation as untrusted. Re-locate the target and retry only after the scope resolves, or create an issue flag instead.",
129098
+ documentMutated
128229
129099
  );
128230
129100
  }
128231
129101
  const afterText = compiledAfter.scope.content.text;
@@ -128237,7 +129107,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128237
129107
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128238
129108
  `actions:rewrite:authoritative-readback-unchanged:${target.handle.scopeId}`,
128239
129109
  "The replacement primitive reported success, but authoritative scope readback showed unchanged text.",
128240
- "Treat the mutation as not applied. Retry with a narrower scope or create an issue flag; do not claim the replacement succeeded."
129110
+ "Treat the mutation as not applied. Retry with a narrower scope or create an issue flag; do not claim the replacement succeeded.",
129111
+ documentMutated
128241
129112
  );
128242
129113
  }
128243
129114
  if (!expectedPresent) {
@@ -128246,7 +129117,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128246
129117
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128247
129118
  `actions:rewrite:authoritative-readback-mismatch:${target.handle.scopeId}`,
128248
129119
  "The replacement primitive reported success, but authoritative scope readback did not contain the proposed text.",
128249
- "Treat the mutation as suspect. Re-read the target, inspect the exported package when available, and retry only with a verified target."
129120
+ "Treat the mutation as suspect. Re-read the target, inspect the exported package when available, and retry only with a verified target.",
129121
+ documentMutated
128250
129122
  );
128251
129123
  }
128252
129124
  return {
@@ -128263,17 +129135,27 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128263
129135
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128264
129136
  };
128265
129137
  }
128266
- function blockedRewriteReadback(result, target, code, message, nextStep) {
129138
+ function blockedRewriteReadback(result, target, code, message, nextStep, documentMutated = false) {
128267
129139
  const detail = blocker(code, "blocked", message, nextStep);
129140
+ const details = documentMutated ? [
129141
+ detail,
129142
+ blockerWithOwner(
129143
+ `actions:rewrite:suspect-mutation:${target.handle.scopeId}`,
129144
+ "blocked",
129145
+ "The document changed even though authoritative target readback failed.",
129146
+ "Abort the plan, inspect the export/readback evidence, and route the target to L08/L07 scope edit-target mapping before retrying.",
129147
+ "L08 semantic scopes and L07 runtime text commands"
129148
+ )
129149
+ ] : [detail];
128268
129150
  return {
128269
129151
  status: "blocked",
128270
129152
  applied: false,
128271
- changed: false,
129153
+ changed: documentMutated,
128272
129154
  target: summarizeTarget(target),
128273
129155
  proposalId: result.proposalId,
128274
- posture: "suspect-readback",
128275
- blockers: Object.freeze([detail.code]),
128276
- blockerDetails: Object.freeze([detail]),
129156
+ posture: documentMutated ? "suspect-mutation" : "suspect-readback",
129157
+ blockers: Object.freeze(details.map((entry) => entry.code)),
129158
+ blockerDetails: Object.freeze(details),
128277
129159
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128278
129160
  };
128279
129161
  }
@@ -128289,11 +129171,23 @@ function summarizeTarget(target) {
128289
129171
  canMark: false
128290
129172
  };
128291
129173
  }
129174
+ if (target.kind === "editable-text") {
129175
+ return {
129176
+ kind: target.targetKind,
129177
+ handle: target.ownerHandle,
129178
+ actionHandle: target.actionHandle,
129179
+ readback: target.readback,
129180
+ canRewriteText: true,
129181
+ canInsertAdjacentText: false,
129182
+ canFlag: false,
129183
+ canMark: false
129184
+ };
129185
+ }
128292
129186
  return {
128293
129187
  kind: target.scope.kind,
128294
129188
  handle: target.handle,
128295
129189
  canRewriteText: canRewriteScopeText(target.scope),
128296
- canInsertAdjacentText: canRewriteScopeText(target.scope),
129190
+ canInsertAdjacentText: canInsertAdjacentScopeText(target.scope),
128297
129191
  canFlag: true,
128298
129192
  canMark: canMarkScope(target.scope)
128299
129193
  };
@@ -128305,6 +129199,34 @@ function tableTextActionsForScope(runtime, handle) {
128305
129199
  });
128306
129200
  return result.actions.filter((action) => action.family === "table-text");
128307
129201
  }
129202
+ function editableTextActionsForScope(runtime, handle) {
129203
+ const bundle = createScopeCompilerService(runtime).compileBundleById(
129204
+ handle.scopeId,
129205
+ currentAuditTimestamp(runtime)
129206
+ );
129207
+ const entries = bundle?.evidence.editableTargets?.entries ?? [];
129208
+ const currentTargets = collectEditableTargetRefs(runtime.getCanonicalDocument());
129209
+ const actions2 = [];
129210
+ for (const entry of entries) {
129211
+ if (entry.kind !== "hyperlink-text" || entry.commandFamily !== "text-leaf" || entry.runtimeCommand.status !== "supported" || !entry.runtimeCommand.actionHandle) {
129212
+ continue;
129213
+ }
129214
+ const currentTarget = currentTargets.find((target) => target.targetKey === entry.targetKey);
129215
+ if (!currentTarget || currentTarget.kind !== "hyperlink-text") continue;
129216
+ const targetState = editableTextTargetState(runtime.getCanonicalDocument(), currentTarget);
129217
+ if (!targetState) continue;
129218
+ actions2.push({
129219
+ kind: "editable-text",
129220
+ targetKind: "hyperlink-text",
129221
+ actionHandle: entry.runtimeCommand.actionHandle,
129222
+ editableTarget: currentTarget,
129223
+ ownerHandle: handle,
129224
+ readback: targetState.readback,
129225
+ selection: targetState.selection
129226
+ });
129227
+ }
129228
+ return Object.freeze(actions2);
129229
+ }
128308
129230
  function findTableAction(runtime, actionHandle) {
128309
129231
  const action = findAnyTableAction(runtime, actionHandle);
128310
129232
  return action?.family === "table-text" ? action : null;
@@ -128324,6 +129246,27 @@ function findAnyTableAction(runtime, actionHandle) {
128324
129246
  }
128325
129247
  return null;
128326
129248
  }
129249
+ function findEditableTextAction(runtime, actionHandle) {
129250
+ if (!actionHandle.startsWith("scope-command:text-leaf:")) return null;
129251
+ const compiler = createScopeCompilerService(runtime);
129252
+ for (const scope of compiler.compileAllScopes()) {
129253
+ const action = editableTextActionsForScope(runtime, scope.handle).find(
129254
+ (candidate) => candidate.actionHandle === actionHandle
129255
+ );
129256
+ if (action) return action;
129257
+ }
129258
+ return null;
129259
+ }
129260
+ function findEditableTextActionByTargetKey(runtime, targetKey) {
129261
+ const compiler = createScopeCompilerService(runtime);
129262
+ for (const scope of compiler.compileAllScopes()) {
129263
+ const action = editableTextActionsForScope(runtime, scope.handle).find(
129264
+ (candidate) => candidate.editableTarget.targetKey === targetKey
129265
+ );
129266
+ if (action) return action;
129267
+ }
129268
+ return null;
129269
+ }
128327
129270
  function readDocumentPlanTarget(runtime) {
128328
129271
  const document2 = createInspectFamily(runtime).inspectDocument();
128329
129272
  return {
@@ -128380,6 +129323,18 @@ function readPlanTarget(runtime, target) {
128380
129323
  ])
128381
129324
  };
128382
129325
  }
129326
+ const editableText = findEditableTextAction(runtime, target.actionHandle);
129327
+ if (editableText) {
129328
+ return {
129329
+ ok: true,
129330
+ target: summarizeTarget(editableText),
129331
+ readback: {
129332
+ text: editableText.readback.text,
129333
+ excerpt: excerpt(editableText.readback.text),
129334
+ isEmpty: editableText.readback.isEmpty
129335
+ }
129336
+ };
129337
+ }
128383
129338
  return readPlanTableAction(runtime, target.actionHandle);
128384
129339
  }
128385
129340
  function readPlanTableAction(runtime, actionHandle) {
@@ -128442,6 +129397,15 @@ function checkPlanStepCapability(runtime, step, before) {
128442
129397
  "Regenerate the plan with a ScopeHandle or opaque actionHandle returned by L09."
128443
129398
  );
128444
129399
  }
129400
+ if (step.kind === "rewrite" && target.kind === "list-item") {
129401
+ return blockerWithOwner(
129402
+ "capability:list-item:authoritative-readback-required",
129403
+ "blocked",
129404
+ "List-item text replacement is not yet backed by an authoritative mutation/readback route.",
129405
+ "Use listOperation for numbering changes, or create an issue/explanation until L08/L07 list-item text replacement is proven.",
129406
+ "L08 semantic scopes and L07 runtime text commands"
129407
+ );
129408
+ }
128445
129409
  if (step.kind === "rewrite" && !target.canRewriteText) {
128446
129410
  return blocker(
128447
129411
  `actions:plan:target-not-rewriteable:${step.id}`,
@@ -128474,7 +129438,20 @@ function checkPlanStepCapability(runtime, step, before) {
128474
129438
  "Use a supported semantic scope or create an issue flag instead."
128475
129439
  );
128476
129440
  }
128477
- if (step.kind === "fieldRefresh" || step.kind === "tocRefresh" || step.kind === "bookmarkEdit" || step.kind === "hyperlinkDestinationEdit") {
129441
+ if (step.kind === "fieldRefresh" || step.kind === "tocRefresh" || step.kind === "bookmarkEdit" || step.kind === "hyperlinkDestinationEdit" || step.kind === "hyperlinkTextEdit") {
129442
+ if (step.kind === "hyperlinkTextEdit") {
129443
+ const resolved2 = resolveTarget(runtime, step.target);
129444
+ if (!resolved2.ok) return resolved2.blockerDetails[0] ?? null;
129445
+ if (resolved2.target.kind !== "editable-text" || resolved2.target.targetKind !== "hyperlink-text") {
129446
+ return blocker(
129447
+ `actions:hyperlink-text-edit:hyperlink-text-handle-required:${step.id}`,
129448
+ "unsupported",
129449
+ "Hyperlink display text plan steps require an exact hyperlink-text actionHandle.",
129450
+ "Regenerate the plan with a scope-command:text-leaf actionHandle returned by ai.actions.locateAll."
129451
+ );
129452
+ }
129453
+ return null;
129454
+ }
128478
129455
  const resolved = resolveScopeExactTarget(runtime, step.target, step.kind);
128479
129456
  if (!resolved.ok) return resolved.blockerDetails[0] ?? null;
128480
129457
  const targetRef = resolveModeledEditableTarget(runtime, resolved.target, step.kind);
@@ -128579,6 +129556,13 @@ function applyPlanStep(runtime, step, plan) {
128579
129556
  actorId: step.actorId ?? plan.actorId,
128580
129557
  origin: step.origin ?? plan.origin
128581
129558
  });
129559
+ case "hyperlinkTextEdit":
129560
+ return createActionsFamily(runtime).actions.hyperlinkTextEdit({
129561
+ target: step.target,
129562
+ text: step.text,
129563
+ actorId: step.actorId ?? plan.actorId,
129564
+ origin: step.origin ?? plan.origin
129565
+ });
128582
129566
  case "listOperation":
128583
129567
  return createActionsFamily(runtime).actions.listOperation({
128584
129568
  target: step.target,
@@ -128895,11 +129879,159 @@ function isTableFamilyScope(kind) {
128895
129879
  return kind === "table" || kind === "table-row" || kind === "table-cell";
128896
129880
  }
128897
129881
  function canRewriteScopeText(scope) {
129882
+ return !isTableFamilyScope(scope.kind) && scope.kind !== "list-item" && (scope.replaceability.level === "full" || scope.replaceability.level === "text-only");
129883
+ }
129884
+ function canInsertAdjacentScopeText(scope) {
128898
129885
  return !isTableFamilyScope(scope.kind) && (scope.replaceability.level === "full" || scope.replaceability.level === "text-only");
128899
129886
  }
129887
+ function scopeRewriteCapabilityBlocker(scope) {
129888
+ if (scope.kind === "list-item") {
129889
+ return blockerWithOwner(
129890
+ "capability:list-item:authoritative-readback-required",
129891
+ "blocked",
129892
+ "List-item text replacement is not yet backed by an authoritative mutation/readback route.",
129893
+ "Use listOperation for numbering changes, or create an issue/explanation until L08/L07 list-item text replacement is proven.",
129894
+ "L08 semantic scopes and L07 runtime text commands"
129895
+ );
129896
+ }
129897
+ if (!canRewriteScopeText(scope)) {
129898
+ return blocker(
129899
+ `actions:rewrite:target-not-rewriteable:${scope.handle.scopeId}`,
129900
+ "unsupported",
129901
+ "The target capability posture does not allow text rewrite.",
129902
+ "Use a supported text target, table text actionHandle, or create an issue flag instead."
129903
+ );
129904
+ }
129905
+ return null;
129906
+ }
128900
129907
  function canMarkScope(scope) {
128901
129908
  return !isTableFamilyScope(scope.kind) && scope.replaceability.level !== "blocked" && scope.replaceability.level !== "preserve-only";
128902
129909
  }
129910
+ function editableTextTargetState(document2, target) {
129911
+ if (target.kind !== "hyperlink-text") return void 0;
129912
+ const resolved = resolveHyperlinkTarget(document2, target);
129913
+ if (!resolved) return void 0;
129914
+ const text = collectInlineText3(resolved.hyperlink.children);
129915
+ return {
129916
+ readback: { text, isEmpty: text.length === 0 },
129917
+ selection: {
129918
+ anchor: resolved.from,
129919
+ head: resolved.to,
129920
+ isCollapsed: resolved.from === resolved.to,
129921
+ activeRange: {
129922
+ kind: "range",
129923
+ from: resolved.from,
129924
+ to: resolved.to,
129925
+ assoc: { start: -1, end: 1 }
129926
+ }
129927
+ }
129928
+ };
129929
+ }
129930
+ function resolveHyperlinkTarget(document2, target) {
129931
+ const parsed = parseBlockInlinePath(target.blockPath);
129932
+ if (!parsed) return null;
129933
+ let blocks = document2.content.children;
129934
+ let block;
129935
+ let row2;
129936
+ let offset = 0;
129937
+ for (const token of parsed) {
129938
+ switch (token.kind) {
129939
+ case "block":
129940
+ for (let index = 0; index < token.index; index += 1) {
129941
+ offset += blockTextLength(blocks[index]);
129942
+ }
129943
+ block = blocks[token.index];
129944
+ row2 = void 0;
129945
+ if (!block) return null;
129946
+ break;
129947
+ case "row":
129948
+ if (block?.type !== "table") return null;
129949
+ row2 = block.rows[token.index];
129950
+ block = void 0;
129951
+ if (!row2) return null;
129952
+ break;
129953
+ case "cell": {
129954
+ const cell = row2?.cells[token.index];
129955
+ if (!cell) return null;
129956
+ blocks = cell.children;
129957
+ block = void 0;
129958
+ row2 = void 0;
129959
+ break;
129960
+ }
129961
+ case "inline": {
129962
+ if (block?.type !== "paragraph") return null;
129963
+ for (let index = 0; index < token.index; index += 1) {
129964
+ offset += inlineTextLength(block.children[index]);
129965
+ }
129966
+ const inline = block.children[token.index];
129967
+ if (inline?.type !== "hyperlink") return null;
129968
+ const length = collectInlineText3(inline.children).length;
129969
+ return { hyperlink: inline, from: offset, to: offset + length };
129970
+ }
129971
+ }
129972
+ }
129973
+ return null;
129974
+ }
129975
+ function parseBlockInlinePath(path) {
129976
+ if (!path.startsWith("main/")) return null;
129977
+ const tokens = [];
129978
+ const re = /(block|row|cell|inline)\[(\d+)\]/gu;
129979
+ let match;
129980
+ while ((match = re.exec(path)) !== null) {
129981
+ const kind = match[1];
129982
+ tokens.push({ kind, index: Number(match[2]) });
129983
+ }
129984
+ return tokens.length > 0 ? Object.freeze(tokens) : null;
129985
+ }
129986
+ function collectInlineText3(inlines) {
129987
+ let text = "";
129988
+ for (const inline of inlines) {
129989
+ switch (inline.type) {
129990
+ case "text":
129991
+ text += inline.text;
129992
+ break;
129993
+ case "hyperlink":
129994
+ case "field":
129995
+ text += collectInlineText3(inline.children);
129996
+ break;
129997
+ default:
129998
+ break;
129999
+ }
130000
+ }
130001
+ return text;
130002
+ }
130003
+ function blockTextLength(block) {
130004
+ if (!block) return 0;
130005
+ switch (block.type) {
130006
+ case "paragraph":
130007
+ return collectInlineText3(block.children).length;
130008
+ case "table":
130009
+ return block.rows.reduce(
130010
+ (rowSum, row2) => rowSum + row2.cells.reduce(
130011
+ (cellSum, cell) => cellSum + cell.children.reduce((blockSum, child) => blockSum + blockTextLength(child), 0),
130012
+ 0
130013
+ ),
130014
+ 0
130015
+ );
130016
+ case "sdt":
130017
+ case "custom_xml":
130018
+ return block.children.reduce((sum, child) => sum + blockTextLength(child), 0);
130019
+ default:
130020
+ return 0;
130021
+ }
130022
+ }
130023
+ function inlineTextLength(inline) {
130024
+ if (!inline) return 0;
130025
+ switch (inline.type) {
130026
+ case "text":
130027
+ return inline.text.length;
130028
+ case "hyperlink":
130029
+ case "field":
130030
+ return collectInlineText3(inline.children).length;
130031
+ default:
130032
+ return 0;
130033
+ }
130034
+ }
128903
130035
  function textMatches(text, query, matchCase) {
128904
130036
  if (matchCase) return text.includes(query);
128905
130037
  return text.toLocaleLowerCase().includes(query.toLocaleLowerCase());
@@ -128958,6 +130090,30 @@ function blockedApplyFromResolution(resolution) {
128958
130090
  blockerDetails: resolution.blockerDetails
128959
130091
  };
128960
130092
  }
130093
+ function withSuspectMutationApplyResult(result, stepOrScopeId, target) {
130094
+ const detail = blockerWithOwner(
130095
+ `actions:plan:suspect-mutation:${stepOrScopeId}`,
130096
+ "blocked",
130097
+ "The document changed even though the action did not return an applied result.",
130098
+ "Abort the remaining plan, inspect authoritative readback/export evidence, and route the target to the owning edit-target/readback layer before retrying.",
130099
+ "L08 semantic scopes and L07 runtime text commands"
130100
+ );
130101
+ return {
130102
+ ...result,
130103
+ status: "blocked",
130104
+ applied: false,
130105
+ changed: true,
130106
+ ...target ? { target } : {},
130107
+ posture: "suspect-mutation",
130108
+ blockers: Object.freeze([...result.blockers ?? [], detail.code]),
130109
+ blockerDetails: Object.freeze([...result.blockerDetails ?? [], detail])
130110
+ };
130111
+ }
130112
+ function isSuspectMutationStep(step) {
130113
+ return step.posture === "suspect-mutation" || (step.blockers ?? []).some(
130114
+ (code) => code.startsWith("actions:plan:suspect-mutation:") || code.startsWith("actions:rewrite:suspect-mutation:")
130115
+ );
130116
+ }
128961
130117
  function blockedPlan(mode, code, category, message, nextStep) {
128962
130118
  const detail = blocker(code, category, message, nextStep);
128963
130119
  return {