@beyondwork/docx-react-component 1.0.124 → 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 +791 -101
  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-A74Y5NE4.js → chunk-4YJVRIUB.js} +52 -21
  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-TY4DIJO3.js → chunk-ESJ2MES5.js} +1 -1
  21. package/dist/{chunk-ZMRO6P3A.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-Q76XPPTA.js → chunk-OHTK7F3F.js} +96 -13
  25. package/dist/{chunk-MPH4ZQS4.js → chunk-QT3LX4FA.js} +321 -51
  26. package/dist/{chunk-7PC6XUNO.js → chunk-TQDQU2E3.js} +2 -2
  27. package/dist/{chunk-4B74ETJI.js → chunk-V6XVZFFH.js} +2 -2
  28. package/dist/{chunk-NAMAWCXN.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 +1341 -193
  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 +51 -20
  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 +36 -12
  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-CNnMHZM9.d.ts → public-types-BEGhv2YR.d.ts} +108 -6
  71. package/dist/{public-types-DajNGKV4.d.cts → 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 +51 -20
  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 +1 -1
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,7 +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;
58605
- var FLD_SIMPLE_INSTR_RE = /<(?:\w+:)?fldSimple\b[^>]*(?:\bw:instr|\binstr)\s*=\s*(["'])([\s\S]*?)\1/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;
58606
58925
  var TOC_FIELD_RE = /\bTOC\b/;
58607
58926
  var REFLIKE_FIELD_RE = /\b(?:HYPERLINK|REF|PAGEREF|NOTEREF)\s+([A-Za-z0-9_:.\-]+)/g;
58608
58927
  var DATA_BINDING_RE = /<(?:\w+:)?dataBinding\b/i;
@@ -58621,11 +58940,22 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58621
58940
  }
58622
58941
  INSTR_TEXT_RE.lastIndex = 0;
58623
58942
  while ((m = INSTR_TEXT_RE.exec(documentXml)) !== null) {
58624
- if (scanInstructionText(m[1] ?? "", retained)) retainAllToc = true;
58943
+ const instrText = m[1] ?? "";
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
+ });
58625
58953
  }
58626
- FLD_SIMPLE_INSTR_RE.lastIndex = 0;
58627
- while ((m = FLD_SIMPLE_INSTR_RE.exec(documentXml)) !== null) {
58628
- if (scanInstructionText(m[2] ?? "", retained)) retainAllToc = true;
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
+ });
58629
58959
  }
58630
58960
  retainRevisionBoundedBookmarks(documentXml, retained);
58631
58961
  return {
@@ -58634,14 +58964,16 @@ function scanBookmarkReferences(documentXml, callerAllowlist = []) {
58634
58964
  retainAll
58635
58965
  };
58636
58966
  }
58637
- function scanInstructionText(instrText, retained) {
58638
- const hasTocField = TOC_FIELD_RE.test(instrText);
58967
+ function scanFieldInstruction(instrText, retained, retainToc) {
58968
+ if (TOC_FIELD_RE.test(instrText)) retainToc();
58639
58969
  REFLIKE_FIELD_RE.lastIndex = 0;
58640
58970
  let r;
58641
58971
  while ((r = REFLIKE_FIELD_RE.exec(instrText)) !== null) {
58642
58972
  if (r[1]) retained.add(r[1]);
58643
58973
  }
58644
- return hasTocField;
58974
+ }
58975
+ function decodeXmlAttribute(value) {
58976
+ return value.replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
58645
58977
  }
58646
58978
  function retainRevisionBoundedBookmarks(documentXml, retained) {
58647
58979
  const starts = /* @__PURE__ */ new Map();
@@ -58994,18 +59326,23 @@ function parseNumberingXml(xml, context) {
58994
59326
  const abstractDefinitions = {};
58995
59327
  const instances = {};
58996
59328
  const numPicBullets = {};
59329
+ const topLevelOrdinals = /* @__PURE__ */ new Map();
58997
59330
  for (const child of numberingElement.children) {
58998
59331
  if (child.type !== "element") {
58999
59332
  continue;
59000
59333
  }
59001
- 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") {
59002
59339
  const rawId = readStringAttr(child, "w:numPicBulletId");
59003
59340
  if (rawId) {
59004
- numPicBullets[rawId] = readNumPicBullet(child, rawId, context);
59341
+ numPicBullets[rawId] = readNumPicBullet(child, rawId, context, childXmlPath);
59005
59342
  }
59006
59343
  continue;
59007
59344
  }
59008
- switch (localName(child.name)) {
59345
+ switch (childName) {
59009
59346
  case "abstractNum": {
59010
59347
  const rawId = readStringAttr(child, "w:abstractNumId");
59011
59348
  if (!rawId) {
@@ -59025,7 +59362,7 @@ function parseNumberingXml(xml, context) {
59025
59362
  const numStyleLink = numStyleLinkEl ? readStringAttr(numStyleLinkEl, "w:val") : void 0;
59026
59363
  abstractDefinitions[abstractNumberingId] = {
59027
59364
  abstractNumberingId,
59028
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId) } : {},
59365
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId, childXmlPath) } : {},
59029
59366
  levels: readLevels(child),
59030
59367
  ...nsid ? { nsid } : {},
59031
59368
  ...multiLevelType ? { multiLevelType } : {},
@@ -59045,7 +59382,7 @@ function parseNumberingXml(xml, context) {
59045
59382
  const numberingInstanceId = toCanonicalNumberingInstanceId(rawId);
59046
59383
  instances[numberingInstanceId] = {
59047
59384
  numberingInstanceId,
59048
- ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId) } : {},
59385
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId, childXmlPath) } : {},
59049
59386
  abstractNumberingId: toCanonicalAbstractNumberingId(rawAbstractId),
59050
59387
  overrides: readOverrides(child)
59051
59388
  };
@@ -59059,15 +59396,16 @@ function parseNumberingXml(xml, context) {
59059
59396
  ...Object.keys(numPicBullets).length > 0 ? { numPicBullets } : {}
59060
59397
  };
59061
59398
  }
59062
- function createNumberingSourceRef(partPath, element, rawId) {
59399
+ function createNumberingSourceRef(partPath, element, rawId, xmlPath) {
59063
59400
  return {
59064
59401
  sourceId: `part:${partPath}#${element}:${rawId}`,
59065
59402
  partPath,
59066
59403
  storyKind: "numbering",
59067
- element
59404
+ element,
59405
+ ...xmlPath !== void 0 ? { xmlPath } : {}
59068
59406
  };
59069
59407
  }
59070
- function readNumPicBullet(node, numPicBulletId, context) {
59408
+ function readNumPicBullet(node, numPicBulletId, context, xmlPath) {
59071
59409
  let widthEmu;
59072
59410
  let heightEmu;
59073
59411
  let mediaId;
@@ -59130,6 +59468,7 @@ function readNumPicBullet(node, numPicBulletId, context) {
59130
59468
  }
59131
59469
  return {
59132
59470
  numPicBulletId,
59471
+ ...context?.partPath !== void 0 ? { sourceRef: createNumberingSourceRef(context.partPath, "numPicBullet", numPicBulletId, xmlPath) } : {},
59133
59472
  rawXml: serializeXmlElementToString(node),
59134
59473
  ...widthEmu !== void 0 ? { widthEmu } : {},
59135
59474
  ...heightEmu !== void 0 ? { heightEmu } : {},
@@ -63096,7 +63435,11 @@ function parseBodyChild(node, sourceXml, relationshipMap, relationships, mediaPa
63096
63435
  switch (localName(child.name)) {
63097
63436
  case "pPr":
63098
63437
  styleId = readParagraphStyleId(child);
63099
- numbering = readParagraphNumbering(child, sourcePartPath);
63438
+ numbering = readParagraphNumbering(
63439
+ child,
63440
+ sourcePartPath,
63441
+ `${sourceXmlPath}/pPr[${countPriorElementSiblingsByName(node, child) + 1}]`
63442
+ );
63100
63443
  alignment = readParagraphAlignment(child);
63101
63444
  spacing = readParagraphSpacing2(child);
63102
63445
  contextualSpacing = readOptionalOnOffParagraphProperty(child, "contextualSpacing");
@@ -64179,7 +64522,7 @@ function readParagraphStyleId(node) {
64179
64522
  }
64180
64523
  return void 0;
64181
64524
  }
64182
- function readParagraphNumbering(node, sourcePartPath) {
64525
+ function readParagraphNumbering(node, sourcePartPath, sourceXmlPath) {
64183
64526
  const numberingProperties = node.children.find(
64184
64527
  (child) => child.type === "element" && localName(child.name) === "numPr"
64185
64528
  );
@@ -64199,16 +64542,22 @@ function readParagraphNumbering(node, sourcePartPath) {
64199
64542
  }
64200
64543
  return {
64201
64544
  numberingInstanceId: toCanonicalNumberingInstanceId(rawInstanceId),
64202
- 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
+ ),
64203
64551
  level: Number.parseInt(rawLevel, 10)
64204
64552
  };
64205
64553
  }
64206
- function createElementSourceRef(partPath, element, node) {
64554
+ function createElementSourceRef(partPath, element, node, xmlPath) {
64207
64555
  return {
64208
64556
  sourceId: `part:${partPath}#${element}:${node.start}`,
64209
64557
  partPath,
64210
64558
  storyKind: storyKindFromPartPath(partPath),
64211
64559
  element,
64560
+ ...xmlPath !== void 0 ? { xmlPath } : {},
64212
64561
  startOffset: node.start,
64213
64562
  endOffset: node.end
64214
64563
  };
@@ -66405,19 +66754,19 @@ function locateTargetRange(document2, surface, target) {
66405
66754
  if (!sdt || sdt.kind !== "sdt_block") return null;
66406
66755
  const paragraph = sdt.children[sdtPath.childIndex];
66407
66756
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66408
- return { from: paragraph.from, to: paragraph.to };
66757
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66409
66758
  }
66410
66759
  const paragraphPath = parseTopLevelParagraphPath(target.blockPath);
66411
66760
  if (paragraphPath) {
66412
66761
  const paragraph = surface[paragraphPath.blockIndex];
66413
66762
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66414
- return { from: paragraph.from, to: paragraph.to };
66763
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66415
66764
  }
66416
66765
  const secondaryParagraphPath = parseSecondaryStoryParagraphPath(target.blockPath);
66417
66766
  if (secondaryParagraphPath) {
66418
66767
  const paragraph = surface[secondaryParagraphPath.blockIndex];
66419
66768
  if (!paragraph || paragraph.kind !== "paragraph") return null;
66420
- return { from: paragraph.from, to: paragraph.to };
66769
+ return textLeafTargetRange(target, paragraph.from, paragraph.to);
66421
66770
  }
66422
66771
  if (target.kind === "textbox-paragraph-text") {
66423
66772
  return {
@@ -66433,6 +66782,18 @@ function locateTargetRange(document2, surface, target) {
66433
66782
  }
66434
66783
  return null;
66435
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
+ }
66436
66797
  function locateHyperlinkDisplayRange(document2, surface, target) {
66437
66798
  const canonical = resolveHyperlinkDisplayPath(document2, target.blockPath);
66438
66799
  if (!canonical) return null;
@@ -66813,6 +67174,8 @@ function sortJson(value) {
66813
67174
 
66814
67175
  // src/runtime/document-runtime.ts
66815
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;
66816
67179
  function getLocalTextPatchMetadata(mapping) {
66817
67180
  const metadata = mapping.metadata?.localTextPatch;
66818
67181
  if (!metadata || typeof metadata !== "object") {
@@ -66985,8 +67348,10 @@ function createDocumentRuntime(options) {
66985
67348
  void upgradeMeasurementProvider(layoutEngine, fontLoader);
66986
67349
  let renderKernelRef = null;
66987
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;
66988
67353
  let viewportBlockRanges = null;
66989
- let viewportRangesKey = serializeViewportRanges(null);
67354
+ let viewportRangesKey = serializeViewportRanges(viewportBlockRanges);
66990
67355
  let viewportBlocksPerPageEstimate = null;
66991
67356
  const EDITING_CORRIDOR_BLOCK_RADIUS = 8;
66992
67357
  const getRuntimeForLayoutFacet = () => {
@@ -67226,10 +67591,11 @@ function createDocumentRuntime(options) {
67226
67591
  const cachedContextAnalyticsSnapshots = /* @__PURE__ */ new Map();
67227
67592
  let lastEmittedContextAnalyticsSnapshots;
67228
67593
  function getCachedFullSurface(document2, nextActiveStory) {
67229
- const activeStoryKey = storyTargetKey(nextActiveStory);
67230
- 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) {
67231
- return cachedFullSurface.snapshot;
67594
+ const cached = getReusableCachedFullSurface(document2, nextActiveStory);
67595
+ if (cached) {
67596
+ return cached;
67232
67597
  }
67598
+ const activeStoryKey = storyTargetKey(nextActiveStory);
67233
67599
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67234
67600
  viewportBlockRanges: null,
67235
67601
  editableTargetsByBlockPath: getEditableTargetsByBlockPath(document2),
@@ -67251,6 +67617,13 @@ function createDocumentRuntime(options) {
67251
67617
  };
67252
67618
  return snapshot;
67253
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
+ }
67254
67627
  function getCachedSurface(document2, nextActiveStory, options2 = {}) {
67255
67628
  const activeStoryKey = storyTargetKey(nextActiveStory);
67256
67629
  const surfaceViewportRanges = "viewportBlockRangesOverride" in options2 ? options2.viewportBlockRangesOverride ?? null : viewportBlockRanges;
@@ -67261,12 +67634,20 @@ function createDocumentRuntime(options) {
67261
67634
  }
67262
67635
  const snapshot = createEditorSurfaceSnapshot(document2, state.selection, nextActiveStory, {
67263
67636
  viewportBlockRanges: surfaceViewportRanges,
67264
- editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPath(document2),
67637
+ editableTargetsByBlockPath: options2.editableTargetsByBlockPathOverride ?? getEditableTargetsByBlockPathForRanges(
67638
+ document2,
67639
+ activeStoryKey,
67640
+ surfaceViewportRanges
67641
+ ),
67265
67642
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
67266
67643
  });
67267
67644
  recordPerfSample("snapshot.surface");
67268
67645
  incrementInvalidationCounter("runtime.snapshot.surfaceMisses");
67269
- const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(snapshot);
67646
+ const enrichedSnapshot = options2.enrichCulledPlaceholders === false ? snapshot : enrichCulledPlaceholdersWithHeights(
67647
+ snapshot,
67648
+ document2,
67649
+ nextActiveStory
67650
+ );
67270
67651
  if (surfaceViewportRanges === null) {
67271
67652
  cachedFullSurface = {
67272
67653
  content: document2.content,
@@ -67324,7 +67705,7 @@ function createDocumentRuntime(options) {
67324
67705
  }
67325
67706
  return -1;
67326
67707
  }
67327
- function cachePatchedLocalTextSurface(surface) {
67708
+ function cachePatchedLocalTextSurface(surface, fullSurfaceForCache) {
67328
67709
  const activeStoryKey = storyTargetKey(activeStory);
67329
67710
  const rangesKey = serializeViewportRanges(surface.viewportBlockRanges);
67330
67711
  cachedSurface = {
@@ -67340,7 +67721,8 @@ function createDocumentRuntime(options) {
67340
67721
  viewportRangesKey: rangesKey,
67341
67722
  snapshot: surface
67342
67723
  };
67343
- if (surface.viewportBlockRanges === null) {
67724
+ const fullSurface = fullSurfaceForCache ?? (surface.viewportBlockRanges === null ? surface : void 0);
67725
+ if (fullSurface) {
67344
67726
  cachedFullSurface = {
67345
67727
  content: state.document.content,
67346
67728
  subParts: state.document.subParts,
@@ -67351,11 +67733,15 @@ function createDocumentRuntime(options) {
67351
67733
  review: state.document.review,
67352
67734
  effectiveMarkupModeProvider,
67353
67735
  activeStoryKey,
67354
- snapshot: surface
67736
+ snapshot: fullSurface
67355
67737
  };
67356
67738
  }
67357
67739
  cachedSurfaceFingerprint = `${activeStoryKey}|${rangesKey}|${String(state.selection.anchor)}:${String(state.selection.head)}`;
67358
67740
  }
67741
+ function createLocalTextCorridorSurfaceFromFullSurface(fullSurface) {
67742
+ const ranges = getSelectionCorridorViewportRanges(fullSurface);
67743
+ return ranges ? createViewportCulledSurfaceFromFullSurface(fullSurface, ranges) : fullSurface;
67744
+ }
67359
67745
  function tryPatchLocalTextSurface(previousSurface, mapping) {
67360
67746
  const tTotal0 = performance.now();
67361
67747
  try {
@@ -67391,6 +67777,13 @@ function createDocumentRuntime(options) {
67391
67777
  perfCounters.increment("surface.localText.patchMiss");
67392
67778
  return null;
67393
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
+ }
67394
67787
  const segmentIndex = block.segments.findIndex(
67395
67788
  (segment2) => segment2.kind === "text" && editFrom >= segment2.from && editTo <= segment2.to
67396
67789
  );
@@ -67498,7 +67891,83 @@ function createDocumentRuntime(options) {
67498
67891
  };
67499
67892
  }
67500
67893
  }
67501
- 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) {
67502
67971
  let heights;
67503
67972
  try {
67504
67973
  heights = layoutFacet.getBlockHeightsTwips();
@@ -67506,17 +67975,19 @@ function createDocumentRuntime(options) {
67506
67975
  return snapshot;
67507
67976
  }
67508
67977
  if (heights.size === 0) return snapshot;
67978
+ const fullSurface = fullSurfaceForPlaceholders ?? getReusableCachedFullSurface(document2, nextActiveStory);
67979
+ if (!fullSurface) return snapshot;
67509
67980
  let changed = false;
67510
67981
  const enrichedBlocks = snapshot.blocks.map((block) => {
67511
67982
  if (block.kind !== "opaque_block" || block.state !== "placeholder-culled") {
67512
67983
  return block;
67513
67984
  }
67514
- const realBlockIdFromOffset = resolveBlockIdFromRuntimeOffset(
67515
- layoutFacet,
67516
- block.from
67985
+ const realBlock = resolveFullSurfaceBlockForPlaceholder(
67986
+ fullSurface,
67987
+ block
67517
67988
  );
67518
- if (!realBlockIdFromOffset) return block;
67519
- const heightTwips = heights.get(realBlockIdFromOffset);
67989
+ if (!realBlock) return block;
67990
+ const heightTwips = heights.get(realBlock.blockId);
67520
67991
  if (typeof heightTwips !== "number" || heightTwips <= 0) return block;
67521
67992
  changed = true;
67522
67993
  return { ...block, placeholderHeightTwips: heightTwips };
@@ -67524,13 +67995,20 @@ function createDocumentRuntime(options) {
67524
67995
  if (!changed) return snapshot;
67525
67996
  return { ...snapshot, blocks: enrichedBlocks };
67526
67997
  }
67527
- function resolveBlockIdFromRuntimeOffset(facet, runtimeOffset) {
67528
- try {
67529
- const frag = facet.getFragmentForOffset?.(runtimeOffset);
67530
- return frag?.blockId ?? null;
67531
- } catch {
67532
- return null;
67998
+ function resolveFullSurfaceBlockForPlaceholder(fullSurface, placeholder) {
67999
+ const index = parsePlaceholderCulledIndex(placeholder.blockId);
68000
+ if (index !== null) {
68001
+ return fullSurface.blocks[index] ?? null;
67533
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;
67534
68012
  }
67535
68013
  function getCachedFieldSnapshot(document2) {
67536
68014
  const blockCount = document2.content.children.length;
@@ -68095,7 +68573,14 @@ function createDocumentRuntime(options) {
68095
68573
  revisionToken: state.revisionToken
68096
68574
  });
68097
68575
  perfCounters.increment("refresh.all");
68098
- 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
+ );
68099
68584
  const snapshot = {
68100
68585
  documentId: state.documentId,
68101
68586
  sessionId: state.sessionId,
@@ -68193,8 +68678,10 @@ function createDocumentRuntime(options) {
68193
68678
  if (options2.forceProjection) {
68194
68679
  cachedFullSurface = void 0;
68195
68680
  }
68196
- const newSurface = viewportBlockRanges !== null && options2.forceProjection !== true ? createViewportCulledSurfaceFromFullSurface(
68197
- 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,
68198
68685
  viewportBlockRanges
68199
68686
  ) : createEditorSurfaceSnapshot(
68200
68687
  state.document,
@@ -68202,11 +68689,21 @@ function createDocumentRuntime(options) {
68202
68689
  activeStory,
68203
68690
  {
68204
68691
  viewportBlockRanges,
68205
- editableTargetsByBlockPath: getEditableTargetsByBlockPath(state.document),
68692
+ editableTargetsByBlockPath: getEditableTargetsByBlockPathForRanges(
68693
+ state.document,
68694
+ activeStoryKey,
68695
+ viewportBlockRanges
68696
+ ),
68206
68697
  ...effectiveMarkupModeProvider ? { getEffectiveMarkupMode: effectiveMarkupModeProvider } : {}
68207
68698
  }
68208
68699
  );
68209
- 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) {
68210
68707
  perfCounters.increment("runtime.viewport.derivedSurfaceRefreshes");
68211
68708
  } else {
68212
68709
  recordPerfSample("snapshot.surface");
@@ -69277,12 +69774,86 @@ function createDocumentRuntime(options) {
69277
69774
  }
69278
69775
  },
69279
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
+ };
69280
69833
  for (const step of plan.steps) {
69281
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
+ );
69282
69853
  const anchor = {
69283
69854
  kind: "range",
69284
- from: step.range.from,
69285
- to: step.range.to,
69855
+ from: dispatchRange.from,
69856
+ to: dispatchRange.to,
69286
69857
  assoc: { start: -1, end: 1 }
69287
69858
  };
69288
69859
  const timestamp = clock();
@@ -69291,6 +69862,8 @@ function createDocumentRuntime(options) {
69291
69862
  {
69292
69863
  type: "text.insert",
69293
69864
  text: step.text,
69865
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69866
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69294
69867
  ...step.formatting ? { formatting: step.formatting } : {},
69295
69868
  origin: createOrigin("api", timestamp)
69296
69869
  },
@@ -69328,10 +69901,28 @@ function createDocumentRuntime(options) {
69328
69901
  emitError(toRuntimeError(error));
69329
69902
  }
69330
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
+ );
69331
69922
  const anchor = {
69332
69923
  kind: "range",
69333
- from: step.range.from,
69334
- to: step.range.to,
69924
+ from: dispatchRange.from,
69925
+ to: dispatchRange.to,
69335
69926
  assoc: { start: -1, end: 1 }
69336
69927
  };
69337
69928
  const timestamp = clock();
@@ -69340,6 +69931,8 @@ function createDocumentRuntime(options) {
69340
69931
  {
69341
69932
  type: "text.insert",
69342
69933
  text: step.text,
69934
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69935
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69343
69936
  ...step.formatting ? { formatting: step.formatting } : {},
69344
69937
  origin: createOrigin("api", timestamp)
69345
69938
  },
@@ -69354,10 +69947,28 @@ function createDocumentRuntime(options) {
69354
69947
  emitError(toRuntimeError(error));
69355
69948
  }
69356
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
+ );
69357
69968
  const anchor = {
69358
69969
  kind: "range",
69359
- from: step.range.from,
69360
- to: step.range.to,
69970
+ from: dispatchRange.from,
69971
+ to: dispatchRange.to,
69361
69972
  assoc: { start: -1, end: 1 }
69362
69973
  };
69363
69974
  const timestamp = clock();
@@ -69365,6 +69976,8 @@ function createDocumentRuntime(options) {
69365
69976
  applyTextCommandInActiveStory(
69366
69977
  {
69367
69978
  type: "text.delete-forward",
69979
+ ...editableTarget?.target ? { editableTarget: editableTarget.target } : {},
69980
+ ...editableTarget?.textTarget ? { textTarget: editableTarget.textTarget } : {},
69368
69981
  origin: createOrigin("api", timestamp)
69369
69982
  },
69370
69983
  {
@@ -70885,9 +71498,13 @@ function createDocumentRuntime(options) {
70885
71498
  applyViewportRanges(getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface));
70886
71499
  }
70887
71500
  const tValidation0 = performance.now();
70888
- 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;
70889
71503
  if (patchedLocalTextSurface) {
70890
- cachePatchedLocalTextSurface(patchedLocalTextSurface);
71504
+ cachePatchedLocalTextSurface(
71505
+ patchedLocalTextSurface,
71506
+ patchedFullLocalTextSurface ?? void 0
71507
+ );
70891
71508
  perfCounters.increment("commit.localTextValidation.storySizeOnly");
70892
71509
  }
70893
71510
  const localTextViewportRanges = useLocalTextCommitSnapshot && !patchedLocalTextSurface ? getSelectionCorridorViewportRanges(cachedRenderSnapshot.surface) : void 0;
@@ -70927,7 +71544,8 @@ function createDocumentRuntime(options) {
70927
71544
  cachedRenderSnapshot = useLocalTextCommitSnapshot ? refreshLocalTextCommitSnapshot(surfaceForValidation, transaction.mapping) : refreshRenderSnapshot();
70928
71545
  perfCounters.increment("commit.refresh.us", Math.round((performance.now() - tRefresh0) * 1e3));
70929
71546
  const tNotify0 = performance.now();
70930
- deferNextContextAnalyticsEmit = useLocalTextCommitSnapshot;
71547
+ const shouldDeferContextAnalyticsEmit = transaction.markDirty && transaction.mapping.steps.length > 0;
71548
+ deferNextContextAnalyticsEmit = shouldDeferContextAnalyticsEmit;
70931
71549
  try {
70932
71550
  notify(previous, state, {
70933
71551
  ...transaction,
@@ -89321,6 +89939,12 @@ function openDocxSync(opts) {
89321
89939
  return loadDocxSessionSync(opts);
89322
89940
  }
89323
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
+
89324
89948
  // src/ui/browser-export.ts
89325
89949
  function withExportDelivery(result, delivery) {
89326
89950
  return {
@@ -89891,6 +90515,9 @@ function createRuntime(args, handlers = {}) {
89891
90515
  )
89892
90516
  ));
89893
90517
  const runtimeSessionState = snapshotExportResolution?.barrier ? applySessionExportBarrier(initialSessionState, snapshotExportResolution.barrier) : initialSessionState;
90518
+ const initialSurfaceViewportBlockRanges = getMountedInitialSurfaceViewportBlockRanges(
90519
+ runtimeSessionState
90520
+ );
89894
90521
  const baseRuntime = createDocumentRuntime({
89895
90522
  documentId: args.documentId,
89896
90523
  initialSessionState: runtimeSessionState,
@@ -89902,6 +90529,7 @@ function createRuntime(args, handlers = {}) {
89902
90529
  fatalError: docxSession?.fatalError,
89903
90530
  protectionSnapshot: docxSession?.protectionSnapshot,
89904
90531
  ...args.source.preloadedLaycacheGraph ? { seedLayoutCache: args.source.preloadedLaycacheGraph } : {},
90532
+ ...initialSurfaceViewportBlockRanges ? { initialSurfaceViewportBlockRanges } : {},
89905
90533
  exportDocx: async (sessionState, options) => {
89906
90534
  if (docxSession) {
89907
90535
  return docxSession.exportDocx(sessionState, options);
@@ -89984,6 +90612,18 @@ function createRuntime(args, handlers = {}) {
89984
90612
  });
89985
90613
  return runtime;
89986
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
+ }
89987
90627
  function createLoadingSnapshot(documentId, readOnly, sourceLabel) {
89988
90628
  return {
89989
90629
  documentId,
@@ -106337,26 +106977,42 @@ function resolveTopBarCommentAvailability(input) {
106337
106977
 
106338
106978
  // src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts
106339
106979
  var import_react39 = require("react");
106340
- function useStatusBarPageFacts(options) {
106341
- const { layoutFacet, selectionPosition, activeStory, renderFrameRevision } = options;
106342
- return (0, import_react39.useMemo)(() => {
106343
- const facet = layoutFacet;
106344
- if (!facet) {
106345
- return {
106346
- displayPageNumber: null,
106347
- pageCount: null,
106348
- measurementFidelity: void 0
106349
- };
106350
- }
106351
- const pageRef = facet.getPageForOffset(selectionPosition, activeStory);
106352
- const displayPageNumber = pageRef !== null && typeof pageRef.pageIndex === "number" ? facet.getDisplayPageNumber(pageRef.pageIndex) ?? pageRef.pageIndex + 1 : null;
106353
- const pageCount = facet.getPageCount();
106980
+ function resolveStatusBarPageFacts(options) {
106981
+ const { layoutFacet: facet, selectionPosition, activeStory, viewportPageIndexRange } = options;
106982
+ if (!facet) {
106354
106983
  return {
106355
- displayPageNumber,
106356
- pageCount,
106357
- measurementFidelity: facet.getMeasurementFidelity()
106984
+ displayPageNumber: null,
106985
+ pageCount: null,
106986
+ measurementFidelity: void 0
106358
106987
  };
106359
- }, [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]);
106360
107016
  }
106361
107017
 
106362
107018
  // src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts
@@ -107364,7 +108020,7 @@ function pageMarkersEqual(a, b) {
107364
108020
  }
107365
108021
  return true;
107366
108022
  }
107367
- function useGeometryVisiblePageIndexRange(input) {
108023
+ function useGeometryVisiblePageIndexRanges(input) {
107368
108024
  const {
107369
108025
  scrollRoot,
107370
108026
  geometryFacet,
@@ -107374,10 +108030,12 @@ function useGeometryVisiblePageIndexRange(input) {
107374
108030
  renderFrameRevision,
107375
108031
  viewportScale
107376
108032
  } = input;
107377
- const [range, setRange] = (0, import_react46.useState)(null);
108033
+ const [ranges, setRanges] = (0, import_react46.useState)({ visiblePageIndexRange: null, viewportPageIndexRange: null });
107378
108034
  (0, import_react46.useEffect)(() => {
107379
108035
  if (!scrollRoot || !geometryFacet) {
107380
- setRange((prev) => prev === null ? prev : null);
108036
+ setRanges(
108037
+ (prev) => prev.visiblePageIndexRange === null && prev.viewportPageIndexRange === null ? prev : { visiblePageIndexRange: null, viewportPageIndexRange: null }
108038
+ );
107381
108039
  return void 0;
107382
108040
  }
107383
108041
  const runtime = scrollRoot.ownerDocument?.defaultView;
@@ -107387,7 +108045,7 @@ function useGeometryVisiblePageIndexRange(input) {
107387
108045
  if (disposed) return;
107388
108046
  const pageCount = layoutFacet?.getPageCount() ?? pageMarkerCount;
107389
108047
  const scale = typeof viewportScale === "number" && Number.isFinite(viewportScale) && viewportScale > 0 ? viewportScale : 1;
107390
- const next = resolveVisiblePageIndexRangeFromViewport({
108048
+ const nextVisible = resolveVisiblePageIndexRangeFromViewport({
107391
108049
  pageCount,
107392
108050
  viewportTopPx: scrollRoot.scrollTop / scale,
107393
108051
  viewportHeightPx: scrollRoot.clientHeight / scale,
@@ -107397,7 +108055,22 @@ function useGeometryVisiblePageIndexRange(input) {
107397
108055
  return page ? page.frame : null;
107398
108056
  }
107399
108057
  });
107400
- 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
+ );
107401
108074
  };
107402
108075
  const schedule = () => {
107403
108076
  if (disposed || rafHandle !== null) return;
@@ -107434,7 +108107,7 @@ function useGeometryVisiblePageIndexRange(input) {
107434
108107
  scrollRoot,
107435
108108
  viewportScale
107436
108109
  ]);
107437
- return range;
108110
+ return ranges;
107438
108111
  }
107439
108112
  function shouldUseCompatibilityPageMarkerScan(input) {
107440
108113
  return !input.geometryFacet || !input.layoutFacet;
@@ -107535,7 +108208,11 @@ function usePageMarkers(options) {
107535
108208
  pageMarkers,
107536
108209
  overscanPages
107537
108210
  });
107538
- const geometryVisiblePageIndexRange = useGeometryVisiblePageIndexRange({
108211
+ const markerViewportPageIndexRange = useVisiblePageIndexRange({
108212
+ pageMarkers,
108213
+ overscanPages: 0
108214
+ });
108215
+ const geometryPageIndexRanges = useGeometryVisiblePageIndexRanges({
107539
108216
  scrollRoot: pageStackScrollRoot,
107540
108217
  geometryFacet,
107541
108218
  layoutFacet,
@@ -107544,7 +108221,8 @@ function usePageMarkers(options) {
107544
108221
  renderFrameRevision,
107545
108222
  viewportScale
107546
108223
  });
107547
- const visiblePageIndexRange = geometryVisiblePageIndexRange ?? markerVisiblePageIndexRange;
108224
+ const visiblePageIndexRange = geometryPageIndexRanges.visiblePageIndexRange ?? markerVisiblePageIndexRange;
108225
+ const viewportPageIndexRange = geometryPageIndexRanges.viewportPageIndexRange ?? markerViewportPageIndexRange;
107548
108226
  const visibleBlockRangesFromPageOffsets = (0, import_react46.useMemo)(
107549
108227
  () => visiblePageIndexRange && layoutFacet ? resolveVisibleBlockRangesFromPageOffsets({
107550
108228
  blocks: snapshot.surface?.blocks ?? [],
@@ -107580,9 +108258,11 @@ function usePageMarkers(options) {
107580
108258
  ]
107581
108259
  );
107582
108260
  const visibleBlockRanges = visibleBlockRangesFromPageOffsets ?? visibleBlockRangesFromPageRange ?? markerVisibleBlockRanges;
108261
+ const totalBlockCount = snapshot.surface?.blocks.length ?? 0;
108262
+ const shouldCullSurface = shouldUseMountedSurfaceViewportCulling(totalBlockCount);
107583
108263
  const visibleRangesKey = (0, import_react46.useMemo)(
107584
- () => visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|"),
107585
- [visibleBlockRanges]
108264
+ () => shouldCullSurface ? visibleBlockRanges.map((r) => `${r.start}:${r.end}`).join("|") : "full",
108265
+ [shouldCullSurface, visibleBlockRanges]
107586
108266
  );
107587
108267
  (0, import_react46.useEffect)(() => {
107588
108268
  if (!layoutFacet) return;
@@ -107591,13 +108271,19 @@ function usePageMarkers(options) {
107591
108271
  layoutFacet.requestViewportRefresh();
107592
108272
  return;
107593
108273
  }
108274
+ if (!shouldCullSurface) {
108275
+ layoutFacet.setVisibleBlockRanges([]);
108276
+ layoutFacet.requestViewportRefresh();
108277
+ return;
108278
+ }
107594
108279
  layoutFacet.setVisibleBlockRanges(visibleBlockRanges);
107595
108280
  layoutFacet.requestViewportRefresh();
107596
- }, [layoutFacet, visibleRangesKey]);
108281
+ }, [layoutFacet, shouldCullSurface, visibleRangesKey]);
107597
108282
  return {
107598
108283
  pageMarkers,
107599
108284
  visibleBlockRanges,
107600
- visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null
108285
+ visiblePageIndexRange: VIEWPORT_CULLING_ENABLED ? visiblePageIndexRange : null,
108286
+ viewportPageIndexRange: VIEWPORT_CULLING_ENABLED ? viewportPageIndexRange : null
107601
108287
  };
107602
108288
  }
107603
108289
 
@@ -110024,11 +110710,20 @@ function TwReviewWorkspace(inputProps) {
110024
110710
  selectionToolbarRootRef
110025
110711
  });
110026
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
+ });
110027
110721
  const grabbedSegmentOffsets = useGrabbedSegmentOffsets(snapshot);
110028
110722
  const statusBarPageFacts = useStatusBarPageFacts({
110029
110723
  layoutFacet: props.layoutFacet,
110030
110724
  selectionPosition,
110031
110725
  activeStory: snapshot.activeStory,
110726
+ viewportPageIndexRange,
110032
110727
  renderFrameRevision
110033
110728
  });
110034
110729
  const hidePageBorderForActiveEditing = isPageWorkspace && snapshot.activeStory.kind === "main" && shouldHidePageBorderForSelection(viewState.selection);
@@ -110054,14 +110749,6 @@ function TwReviewWorkspace(inputProps) {
110054
110749
  });
110055
110750
  const suppressFloatingToolDuringEditorInput = viewState.editorRole === "editor" && viewState.selection.isCollapsed;
110056
110751
  const shouldRenderFloatingSelectionTool = chromeVisibility.selectionOverlay && gatedSelectionTool && !suppressFloatingToolDuringEditorInput && shouldRenderSelectionToolKind(scopedChromePolicy, gatedSelectionTool.kind);
110057
- const { visiblePageIndexRange } = usePageMarkers({
110058
- pageStackScrollRoot,
110059
- snapshot,
110060
- layoutFacet: props.layoutFacet,
110061
- geometryFacet: props.geometryFacet,
110062
- renderFrameRevision,
110063
- viewportScale: zoomScale
110064
- });
110065
110752
  const { dismissSelectionToolbar, runWithSelectionToolbarDismiss } = useWorkspaceSideEffects({
110066
110753
  layoutFacet: props.layoutFacet,
110067
110754
  activeParagraphLayout,
@@ -127403,6 +128090,17 @@ var hyperlinkDestinationEditMetadata = actionMethodMetadata(
127403
128090
  expectedDelta: "hyperlink destination changes"
127404
128091
  }
127405
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
+ );
127406
128104
  var listOperationMetadata = actionMethodMetadata(
127407
128105
  "listOperation",
127408
128106
  "mutate",
@@ -127462,6 +128160,7 @@ var ACTION_METHODS = Object.freeze([
127462
128160
  "tocRefresh",
127463
128161
  "bookmarkEdit",
127464
128162
  "hyperlinkDestinationEdit",
128163
+ "hyperlinkTextEdit",
127465
128164
  "listOperation",
127466
128165
  "tableFragment",
127467
128166
  "tableSelection",
@@ -127471,6 +128170,9 @@ var DEFAULT_LOCATE_LIMIT = 20;
127471
128170
  var DEFAULT_REWRITE_ALL_LIMIT = 10;
127472
128171
  var DEFAULT_TABLE_TEXT_SCOPE_LIMIT = 3;
127473
128172
  var DEFAULT_PLAN_STEP_LIMIT = 20;
128173
+ function documentContentHash(runtime) {
128174
+ return JSON.stringify(runtime.getCanonicalDocument().content);
128175
+ }
127474
128176
  function createActionsFamily(runtime) {
127475
128177
  const category = {
127476
128178
  discover(input) {
@@ -127717,6 +128419,14 @@ function createActionsFamily(runtime) {
127717
128419
  ...readback ? { text: readback.text, excerpt: excerpt(readback.text) } : {}
127718
128420
  };
127719
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
+ }
127720
128430
  const text = resolved.target.scope.content.text;
127721
128431
  return {
127722
128432
  status: "read",
@@ -127797,6 +128507,31 @@ function createActionsFamily(runtime) {
127797
128507
  input
127798
128508
  );
127799
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
+ },
127800
128535
  listOperation(input) {
127801
128536
  return applyListOperation(runtime, input);
127802
128537
  },
@@ -127845,6 +128580,7 @@ function runPlan(runtime, input) {
127845
128580
  for (const step of input.steps) {
127846
128581
  const result = runPlanStep(runtime, mode, step, input);
127847
128582
  results.push(result);
128583
+ if (isSuspectMutationStep(result)) break;
127848
128584
  if (stopOnBlocker && (result.status === "blocked" || result.status === "unsupported")) {
127849
128585
  break;
127850
128586
  }
@@ -127909,24 +128645,27 @@ function runPlanStep(runtime, mode, step, plan) {
127909
128645
  ...before.readback ? { beforeReadback: before.readback } : {}
127910
128646
  };
127911
128647
  }
128648
+ const documentHashBeforeApply = documentContentHash(runtime);
127912
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;
127913
128652
  const after = step.kind === "flag" ? before : step.target ? readPlanTarget(runtime, step.target) : before;
127914
128653
  return {
127915
128654
  id: step.id,
127916
128655
  kind: step.kind,
127917
- status: applied.status === "unsupported" ? "unsupported" : applied.applied ? "applied" : "blocked",
127918
- applied: applied.applied,
127919
- changed: applied.changed,
127920
- ...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 } : {},
127921
128660
  ...before.tableAction ? { tableAction: before.tableAction } : {},
127922
128661
  ...before.readback ? { beforeReadback: before.readback } : {},
127923
128662
  ...after.ok && after.readback ? { afterReadback: after.readback } : {},
127924
- ...applied.proposalId ? { proposalId: applied.proposalId } : {},
127925
- ...applied.posture ? { posture: applied.posture } : {},
127926
- ...applied.blockers ? { blockers: applied.blockers } : {},
127927
- ...applied.blockerDetails ? { blockerDetails: applied.blockerDetails } : {},
127928
- ...applied.auditReference ? { auditReference: applied.auditReference } : {},
127929
- ...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 } : {}
127930
128669
  };
127931
128670
  }
127932
128671
  function runPlanTableActionStep(runtime, mode, step, plan) {
@@ -128054,6 +128793,23 @@ function locateAll(runtime, input) {
128054
128793
  isEmpty: text.trim().length === 0
128055
128794
  });
128056
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
+ }
128057
128813
  if (matches.length < limit && shouldScanTableText) {
128058
128814
  const tableTextScopeLimit = Math.max(
128059
128815
  0,
@@ -128088,23 +128844,27 @@ function locateAll(runtime, input) {
128088
128844
  function resolveTarget(runtime, target) {
128089
128845
  if ("actionHandle" in target) {
128090
128846
  const action = findTableAction(runtime, target.actionHandle);
128091
- if (!action) {
128092
- return blockedResolution(
128093
- `actions:target:action-handle-not-found:${target.actionHandle}`,
128094
- "unresolved-target",
128095
- "No current table text action matches the supplied actionHandle.",
128096
- "Call ai.actions.locateAll or ai.listTableActions again and retry with a fresh actionHandle."
128097
- );
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 } };
128098
128857
  }
128099
- if (action.family !== "table-text") {
128100
- return blockedResolution(
128101
- `actions:target:action-handle-not-text:${target.actionHandle}`,
128102
- "unsupported",
128103
- "This actionHandle is not a table text action.",
128104
- "Use table structure handles with ai.applyTableAction, or use a table text actionHandle for rewrite."
128105
- );
128858
+ const editableTextAction = findEditableTextAction(runtime, target.actionHandle);
128859
+ if (editableTextAction) {
128860
+ return { ok: true, target: editableTextAction };
128106
128861
  }
128107
- 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
+ );
128108
128868
  }
128109
128869
  if ("handle" in target) {
128110
128870
  const compiled = createScopeCompilerService(runtime).compileScopeById(target.handle.scopeId);
@@ -128189,7 +128949,21 @@ function applyRewrite(runtime, target, input) {
128189
128949
  ...result2.afterReadback ? { afterReadback: result2.afterReadback } : {}
128190
128950
  };
128191
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
+ }
128192
128965
  const beforeText = target.scope.content.text;
128966
+ const documentHashBeforeApply = documentContentHash(runtime);
128193
128967
  const result = createReplacementFamily(runtime).applyReplacementScope({
128194
128968
  targetScopeId: target.handle.scopeId,
128195
128969
  operation: "replace",
@@ -128201,7 +128975,22 @@ function applyRewrite(runtime, target, input) {
128201
128975
  ...input.origin ? { origin: input.origin } : {},
128202
128976
  ...input.proposalId ? { proposalId: input.proposalId } : {}
128203
128977
  });
128204
- 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
+ );
128205
128994
  }
128206
128995
  function projectApplyResult(result, target) {
128207
128996
  return {
@@ -128222,7 +129011,79 @@ function projectApplyResult(result, target) {
128222
129011
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128223
129012
  };
128224
129013
  }
128225
- 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) {
128226
129087
  if (!result.applied) return projectApplyResult(result, target);
128227
129088
  const compiledAfter = createScopeCompilerService(runtime).compileScopeById(
128228
129089
  target.handle.scopeId
@@ -128233,7 +129094,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128233
129094
  target,
128234
129095
  `actions:rewrite:authoritative-readback-unresolvable:${target.handle.scopeId}`,
128235
129096
  "The replacement primitive reported success, but the target scope could not be re-read afterwards.",
128236
- "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
128237
129099
  );
128238
129100
  }
128239
129101
  const afterText = compiledAfter.scope.content.text;
@@ -128245,7 +129107,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128245
129107
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128246
129108
  `actions:rewrite:authoritative-readback-unchanged:${target.handle.scopeId}`,
128247
129109
  "The replacement primitive reported success, but authoritative scope readback showed unchanged text.",
128248
- "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
128249
129112
  );
128250
129113
  }
128251
129114
  if (!expectedPresent) {
@@ -128254,7 +129117,8 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128254
129117
  { ...target, scope: compiledAfter.scope, handle: compiledAfter.scope.handle },
128255
129118
  `actions:rewrite:authoritative-readback-mismatch:${target.handle.scopeId}`,
128256
129119
  "The replacement primitive reported success, but authoritative scope readback did not contain the proposed text.",
128257
- "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
128258
129122
  );
128259
129123
  }
128260
129124
  return {
@@ -128271,17 +129135,27 @@ function projectRewriteScopeResult(runtime, result, target, beforeText, proposed
128271
129135
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128272
129136
  };
128273
129137
  }
128274
- function blockedRewriteReadback(result, target, code, message, nextStep) {
129138
+ function blockedRewriteReadback(result, target, code, message, nextStep, documentMutated = false) {
128275
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];
128276
129150
  return {
128277
129151
  status: "blocked",
128278
129152
  applied: false,
128279
- changed: false,
129153
+ changed: documentMutated,
128280
129154
  target: summarizeTarget(target),
128281
129155
  proposalId: result.proposalId,
128282
- posture: "suspect-readback",
128283
- blockers: Object.freeze([detail.code]),
128284
- 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),
128285
129159
  ...result.auditReference ? { auditReference: result.auditReference } : {}
128286
129160
  };
128287
129161
  }
@@ -128297,11 +129171,23 @@ function summarizeTarget(target) {
128297
129171
  canMark: false
128298
129172
  };
128299
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
+ }
128300
129186
  return {
128301
129187
  kind: target.scope.kind,
128302
129188
  handle: target.handle,
128303
129189
  canRewriteText: canRewriteScopeText(target.scope),
128304
- canInsertAdjacentText: canRewriteScopeText(target.scope),
129190
+ canInsertAdjacentText: canInsertAdjacentScopeText(target.scope),
128305
129191
  canFlag: true,
128306
129192
  canMark: canMarkScope(target.scope)
128307
129193
  };
@@ -128313,6 +129199,34 @@ function tableTextActionsForScope(runtime, handle) {
128313
129199
  });
128314
129200
  return result.actions.filter((action) => action.family === "table-text");
128315
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
+ }
128316
129230
  function findTableAction(runtime, actionHandle) {
128317
129231
  const action = findAnyTableAction(runtime, actionHandle);
128318
129232
  return action?.family === "table-text" ? action : null;
@@ -128332,6 +129246,27 @@ function findAnyTableAction(runtime, actionHandle) {
128332
129246
  }
128333
129247
  return null;
128334
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
+ }
128335
129270
  function readDocumentPlanTarget(runtime) {
128336
129271
  const document2 = createInspectFamily(runtime).inspectDocument();
128337
129272
  return {
@@ -128388,6 +129323,18 @@ function readPlanTarget(runtime, target) {
128388
129323
  ])
128389
129324
  };
128390
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
+ }
128391
129338
  return readPlanTableAction(runtime, target.actionHandle);
128392
129339
  }
128393
129340
  function readPlanTableAction(runtime, actionHandle) {
@@ -128450,6 +129397,15 @@ function checkPlanStepCapability(runtime, step, before) {
128450
129397
  "Regenerate the plan with a ScopeHandle or opaque actionHandle returned by L09."
128451
129398
  );
128452
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
+ }
128453
129409
  if (step.kind === "rewrite" && !target.canRewriteText) {
128454
129410
  return blocker(
128455
129411
  `actions:plan:target-not-rewriteable:${step.id}`,
@@ -128482,7 +129438,20 @@ function checkPlanStepCapability(runtime, step, before) {
128482
129438
  "Use a supported semantic scope or create an issue flag instead."
128483
129439
  );
128484
129440
  }
128485
- 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
+ }
128486
129455
  const resolved = resolveScopeExactTarget(runtime, step.target, step.kind);
128487
129456
  if (!resolved.ok) return resolved.blockerDetails[0] ?? null;
128488
129457
  const targetRef = resolveModeledEditableTarget(runtime, resolved.target, step.kind);
@@ -128587,6 +129556,13 @@ function applyPlanStep(runtime, step, plan) {
128587
129556
  actorId: step.actorId ?? plan.actorId,
128588
129557
  origin: step.origin ?? plan.origin
128589
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
+ });
128590
129566
  case "listOperation":
128591
129567
  return createActionsFamily(runtime).actions.listOperation({
128592
129568
  target: step.target,
@@ -128903,11 +129879,159 @@ function isTableFamilyScope(kind) {
128903
129879
  return kind === "table" || kind === "table-row" || kind === "table-cell";
128904
129880
  }
128905
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) {
128906
129885
  return !isTableFamilyScope(scope.kind) && (scope.replaceability.level === "full" || scope.replaceability.level === "text-only");
128907
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
+ }
128908
129907
  function canMarkScope(scope) {
128909
129908
  return !isTableFamilyScope(scope.kind) && scope.replaceability.level !== "blocked" && scope.replaceability.level !== "preserve-only";
128910
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
+ }
128911
130035
  function textMatches(text, query, matchCase) {
128912
130036
  if (matchCase) return text.includes(query);
128913
130037
  return text.toLocaleLowerCase().includes(query.toLocaleLowerCase());
@@ -128966,6 +130090,30 @@ function blockedApplyFromResolution(resolution) {
128966
130090
  blockerDetails: resolution.blockerDetails
128967
130091
  };
128968
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
+ }
128969
130117
  function blockedPlan(mode, code, category, message, nextStep) {
128970
130118
  const detail = blocker(code, category, message, nextStep);
128971
130119
  return {