@beyondwork/docx-react-component 1.0.133 → 1.0.134

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 (70) hide show
  1. package/dist/api/public-types.cjs +3 -1
  2. package/dist/api/public-types.d.cts +1 -1
  3. package/dist/api/public-types.d.ts +1 -1
  4. package/dist/api/public-types.js +1 -1
  5. package/dist/api/v3.cjs +688 -45
  6. package/dist/api/v3.d.cts +2 -2
  7. package/dist/api/v3.d.ts +2 -2
  8. package/dist/api/v3.js +3 -3
  9. package/dist/{chunk-S3PEKX6H.js → chunk-3YR47WTD.js} +53 -547
  10. package/dist/{chunk-57HTKX3P.js → chunk-74R5B2EZ.js} +1 -1
  11. package/dist/{chunk-KL4TZSZV.js → chunk-7Y6JCIK3.js} +1 -1
  12. package/dist/{chunk-3JEE5RJU.js → chunk-EBSI6VQX.js} +457 -16
  13. package/dist/{chunk-OTRVGNZQ.js → chunk-ESEEWELA.js} +547 -2
  14. package/dist/{chunk-224TSMEB.js → chunk-IJD6D7HU.js} +137 -41
  15. package/dist/{chunk-CVSD3UNK.js → chunk-O4EDZR44.js} +3 -1
  16. package/dist/{chunk-ZFCZ7XXH.js → chunk-VA24T4EB.js} +1 -1
  17. package/dist/core/commands/formatting-commands.d.cts +1 -1
  18. package/dist/core/commands/formatting-commands.d.ts +1 -1
  19. package/dist/core/commands/image-commands.d.cts +1 -1
  20. package/dist/core/commands/image-commands.d.ts +1 -1
  21. package/dist/core/commands/section-layout-commands.d.cts +1 -1
  22. package/dist/core/commands/section-layout-commands.d.ts +1 -1
  23. package/dist/core/commands/style-commands.d.cts +1 -1
  24. package/dist/core/commands/style-commands.d.ts +1 -1
  25. package/dist/core/commands/table-structure-commands.d.cts +1 -1
  26. package/dist/core/commands/table-structure-commands.d.ts +1 -1
  27. package/dist/core/commands/text-commands.d.cts +1 -1
  28. package/dist/core/commands/text-commands.d.ts +1 -1
  29. package/dist/core/selection/mapping.d.cts +1 -1
  30. package/dist/core/selection/mapping.d.ts +1 -1
  31. package/dist/core/state/editor-state.d.cts +1 -1
  32. package/dist/core/state/editor-state.d.ts +1 -1
  33. package/dist/index.cjs +1289 -615
  34. package/dist/index.d.cts +4 -4
  35. package/dist/index.d.ts +4 -4
  36. package/dist/index.js +105 -19
  37. package/dist/io/docx-session.d.cts +3 -3
  38. package/dist/io/docx-session.d.ts +3 -3
  39. package/dist/{loader-B2H99237.d.cts → loader-CK3lZy4h.d.cts} +2 -2
  40. package/dist/{loader-DfTjqVwn.d.ts → loader-CQXplstv.d.ts} +2 -2
  41. package/dist/{public-types-S8gTYwKo.d.cts → public-types-BR1SYK2F.d.cts} +140 -3
  42. package/dist/{public-types-B5lOUIrP.d.ts → public-types-DXNZVKrS.d.ts} +140 -3
  43. package/dist/public-types.cjs +3 -1
  44. package/dist/public-types.d.cts +1 -1
  45. package/dist/public-types.d.ts +1 -1
  46. package/dist/public-types.js +1 -1
  47. package/dist/runtime/collab.d.cts +2 -2
  48. package/dist/runtime/collab.d.ts +2 -2
  49. package/dist/runtime/document-runtime.cjs +591 -54
  50. package/dist/runtime/document-runtime.d.cts +1 -1
  51. package/dist/runtime/document-runtime.d.ts +1 -1
  52. package/dist/runtime/document-runtime.js +4 -4
  53. package/dist/{session-CBDIOYXA.d.ts → session-C9UjrhJF.d.ts} +2 -2
  54. package/dist/{session-CR2A1hGZ.d.cts → session-CSbwkgII.d.cts} +2 -2
  55. package/dist/session.d.cts +4 -4
  56. package/dist/session.d.ts +4 -4
  57. package/dist/tailwind.cjs +54 -546
  58. package/dist/tailwind.d.cts +1 -1
  59. package/dist/tailwind.d.ts +1 -1
  60. package/dist/tailwind.js +4 -4
  61. package/dist/{types-yty2K-hk.d.cts → types-CZtAueri.d.cts} +1 -1
  62. package/dist/{types-B-90ywjU.d.ts → types-RzkCXDNV.d.ts} +1 -1
  63. package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +2 -2
  64. package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +2 -2
  65. package/dist/ui-tailwind/editor-surface/search-plugin.js +2 -2
  66. package/dist/ui-tailwind.cjs +54 -546
  67. package/dist/ui-tailwind.d.cts +2 -2
  68. package/dist/ui-tailwind.d.ts +2 -2
  69. package/dist/ui-tailwind.js +4 -4
  70. package/package.json +1 -1
package/dist/api/v3.cjs CHANGED
@@ -33897,16 +33897,12 @@ function replaceTextCapability(scope, context) {
33897
33897
  );
33898
33898
  }
33899
33899
  if (scope.kind === "scope") {
33900
- if (scope.workflow.effectiveMode === "suggest") {
33901
- return unsupported(
33902
- "compile-refused:scope:multi-paragraph-suggesting-not-implemented",
33903
- ["compile-refused:scope:multi-paragraph-suggesting-not-implemented"],
33904
- ["guard:suggest-mode", ...evidenceWarnings(context)]
33905
- );
33906
- }
33907
33900
  return supported(
33908
33901
  "compile-supported:scope:multi-paragraph-text-replace",
33909
- evidenceWarnings(context)
33902
+ [
33903
+ ...scope.workflow.effectiveMode === "suggest" ? ["guard:suggest-mode"] : [],
33904
+ ...evidenceWarnings(context)
33905
+ ]
33910
33906
  );
33911
33907
  }
33912
33908
  if (!PARAGRAPH_LIKE.has(scope.kind)) {
@@ -33960,34 +33956,24 @@ function replaceFragmentCapability(scope, context) {
33960
33956
  );
33961
33957
  }
33962
33958
  if (scope.kind === "scope") {
33963
- if (scope.workflow.effectiveMode === "suggest") {
33964
- return unsupported(
33965
- "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented",
33966
- [
33967
- "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented"
33968
- ],
33969
- ["guard:suggest-mode", ...evidenceWarnings(context)]
33970
- );
33971
- }
33972
33959
  return supported(
33973
33960
  "compile-supported:scope:multi-paragraph-fragment-replace",
33974
- evidenceWarnings(context)
33961
+ [
33962
+ ...scope.workflow.effectiveMode === "suggest" ? ["guard:suggest-mode"] : [],
33963
+ ...evidenceWarnings(context)
33964
+ ]
33975
33965
  );
33976
33966
  }
33977
33967
  if (!PARAGRAPH_LIKE.has(scope.kind)) {
33978
33968
  const reason = `compile-refused:${scope.kind}`;
33979
33969
  return unsupported(reason, [reason], evidenceWarnings(context));
33980
33970
  }
33981
- if (scope.workflow.effectiveMode === "suggest") {
33982
- return unsupported(
33983
- `compile-refused:${scope.kind}:structured-suggesting-not-implemented`,
33984
- [`compile-refused:${scope.kind}:structured-suggesting-not-implemented`],
33985
- ["guard:suggest-mode"]
33986
- );
33987
- }
33988
33971
  return supported(
33989
- "compile-supported:paragraph-like:fragment-replace",
33990
- evidenceWarnings(context)
33972
+ scope.workflow.effectiveMode === "suggest" ? "compile-supported:paragraph-like:fragment-replace-tracked" : "compile-supported:paragraph-like:fragment-replace",
33973
+ [
33974
+ ...scope.workflow.effectiveMode === "suggest" ? ["guard:suggest-mode"] : [],
33975
+ ...evidenceWarnings(context)
33976
+ ]
33991
33977
  );
33992
33978
  }
33993
33979
  function formattingCapability(scope, context) {
@@ -35262,6 +35248,14 @@ function supportedNonTextCommandEvidence(target) {
35262
35248
  if (target.commandFamily === "link-bookmark") {
35263
35249
  return linkBookmarkCommandEvidence(target, []);
35264
35250
  }
35251
+ if (target.commandFamily === "object" && isImageObjectTarget(target) && typeof target.object?.mediaId === "string" && target.object.mediaId.length > 0 && onlyBlockers(target.posture.blockers, ["unmodeled-target"])) {
35252
+ return {
35253
+ status: "supported",
35254
+ commandFamily: target.commandFamily,
35255
+ intents: commandIntentsForTarget(target),
35256
+ reason: "l07:image-layout-target-supported"
35257
+ };
35258
+ }
35265
35259
  return null;
35266
35260
  }
35267
35261
  function onlyBlockers(blockers, allowed) {
@@ -40380,11 +40374,9 @@ function compileParagraphReplacement(entry, proposed, options) {
40380
40374
  };
40381
40375
  }
40382
40376
  if (proposed.proposedContent.kind === "structured") {
40383
- if (options.posture === "suggest-mode") {
40384
- return null;
40385
- }
40386
40377
  const fragment = proposed.proposedContent.structured;
40387
40378
  if (!isStructuredReplacementContent(fragment)) return null;
40379
+ const stepKind = options.posture === "suggest-mode" ? "fragment-replace-tracked" : "fragment-replace";
40388
40380
  const blockCount = fragment.blocks.length;
40389
40381
  const summaryScope = rangeKind === "inline-marker" ? `paragraph #${entry.blockIndex} inline-marker range [${effectiveRange.from}..${effectiveRange.to}]` : rangeKind === "opaque-preserving-text" ? `paragraph #${entry.blockIndex} opaque-preserving text range [${effectiveRange.from}..${effectiveRange.to}]` : `paragraph #${entry.blockIndex}`;
40390
40382
  const actionVerb = proposed.operation === "insert-before" ? "insert before" : proposed.operation === "insert-after" ? "insert after" : "replace";
@@ -40395,8 +40387,8 @@ function compileParagraphReplacement(entry, proposed, options) {
40395
40387
  operation: proposed.operation,
40396
40388
  steps: Object.freeze([
40397
40389
  {
40398
- kind: "fragment-replace",
40399
- summary: actionSummary,
40390
+ kind: stepKind,
40391
+ summary: stepKind === "fragment-replace" ? actionSummary : `suggest-mode ${actionSummary}`,
40400
40392
  ...textLeafEditableTargetHint(entry, blockRange) ? { editableTargetHint: textLeafEditableTargetHint(entry, blockRange) } : {},
40401
40393
  range: { from: operationRange.from, to: operationRange.to },
40402
40394
  fragment
@@ -40483,7 +40475,7 @@ function compileScopeKind(entry, options) {
40483
40475
  };
40484
40476
  }
40485
40477
  function compileScopeReplacement(entry, proposed, options) {
40486
- if (entry.handle.provenance !== "marker-backed" || proposed.operation !== "replace" || options.posture !== "direct-edit") {
40478
+ if (entry.handle.provenance !== "marker-backed" || proposed.operation !== "replace") {
40487
40479
  return null;
40488
40480
  }
40489
40481
  const markerRange = buildScopePositionMap(options.document).markerScopes.get(
@@ -40492,14 +40484,15 @@ function compileScopeReplacement(entry, proposed, options) {
40492
40484
  if (!markerRange) return null;
40493
40485
  if (proposed.proposedContent.kind === "text") {
40494
40486
  const text = proposed.proposedContent.text ?? "";
40487
+ const stepKind = options.posture === "suggest-mode" ? "text-insert-tracked" : "text-replace";
40495
40488
  return {
40496
40489
  scopeId: entry.handle.scopeId,
40497
40490
  targetKind: "scope",
40498
40491
  operation: proposed.operation,
40499
40492
  steps: Object.freeze([
40500
40493
  {
40501
- kind: "text-replace",
40502
- summary: `replace multi-paragraph scope ${entry.handle.scopeId} text [${markerRange.from}..${markerRange.to}] (len ${text.length})`,
40494
+ kind: stepKind,
40495
+ summary: stepKind === "text-replace" ? `replace multi-paragraph scope ${entry.handle.scopeId} text [${markerRange.from}..${markerRange.to}] (len ${text.length})` : `suggest-mode replace multi-paragraph scope ${entry.handle.scopeId} text [${markerRange.from}..${markerRange.to}] (len ${text.length})`,
40503
40496
  range: { from: markerRange.from, to: markerRange.to },
40504
40497
  text,
40505
40498
  ...proposed.formatting ? { formatting: proposed.formatting } : {}
@@ -40512,14 +40505,15 @@ function compileScopeReplacement(entry, proposed, options) {
40512
40505
  if (proposed.proposedContent.kind === "structured") {
40513
40506
  const fragment = proposed.proposedContent.structured;
40514
40507
  if (!isStructuredReplacementContent(fragment)) return null;
40508
+ const stepKind = options.posture === "suggest-mode" ? "fragment-replace-tracked" : "fragment-replace";
40515
40509
  return {
40516
40510
  scopeId: entry.handle.scopeId,
40517
40511
  targetKind: "scope",
40518
40512
  operation: proposed.operation,
40519
40513
  steps: Object.freeze([
40520
40514
  {
40521
- kind: "fragment-replace",
40522
- summary: `replace multi-paragraph scope ${entry.handle.scopeId} with structured fragment [${markerRange.from}..${markerRange.to}] (${fragment.blocks.length} block(s))`,
40515
+ kind: stepKind,
40516
+ summary: stepKind === "fragment-replace" ? `replace multi-paragraph scope ${entry.handle.scopeId} with structured fragment [${markerRange.from}..${markerRange.to}] (${fragment.blocks.length} block(s))` : `suggest-mode replace multi-paragraph scope ${entry.handle.scopeId} with structured fragment [${markerRange.from}..${markerRange.to}] (${fragment.blocks.length} block(s))`,
40523
40517
  range: { from: markerRange.from, to: markerRange.to },
40524
40518
  fragment
40525
40519
  }
@@ -40901,6 +40895,99 @@ function paragraphFirstMarkerStart(paragraph, knownScopeIds) {
40901
40895
  }
40902
40896
  return null;
40903
40897
  }
40898
+ function paragraphHasMarkerEnd(paragraph, scopeId) {
40899
+ return paragraph.children.some(
40900
+ (child) => child.type === "scope_marker_end" && child.scopeId === scopeId
40901
+ );
40902
+ }
40903
+ function paragraphSameParagraphMarkerScopeId(paragraph, knownScopeIds) {
40904
+ const markerScopeId = paragraphFirstMarkerStart(paragraph, knownScopeIds);
40905
+ if (!markerScopeId) return null;
40906
+ return paragraphHasMarkerEnd(paragraph, markerScopeId) ? markerScopeId : null;
40907
+ }
40908
+ function markerStableRefOverride(markerScopeId, semanticPath, overlay) {
40909
+ const hint = stableRefHintForScopeId(markerScopeId, overlay);
40910
+ if (hint === "semantic-path") {
40911
+ return {
40912
+ kind: "semantic-path",
40913
+ value: semanticPath.join("/")
40914
+ };
40915
+ }
40916
+ return { kind: "scope-id", value: markerScopeId };
40917
+ }
40918
+ function enumerateNestedMarkerBackedParagraphs(blocks, input) {
40919
+ const out = [];
40920
+ for (let childIndex = 0; childIndex < blocks.length; childIndex += 1) {
40921
+ const block = blocks[childIndex];
40922
+ if (!block) continue;
40923
+ if (block.type === "paragraph") {
40924
+ const markerScopeId = paragraphSameParagraphMarkerScopeId(
40925
+ block,
40926
+ input.knownOverlayScopeIds
40927
+ );
40928
+ if (!markerScopeId) continue;
40929
+ const kind = detectParagraphKind(block);
40930
+ const semanticPath = [
40931
+ ...input.semanticPrefix,
40932
+ kind,
40933
+ String(childIndex)
40934
+ ];
40935
+ const handle = buildHandle(
40936
+ markerScopeId,
40937
+ input.documentId,
40938
+ semanticPath,
40939
+ "marker-backed",
40940
+ "marker-backed",
40941
+ input.parentScopeId,
40942
+ markerStableRefOverride(markerScopeId, semanticPath, input.overlay)
40943
+ );
40944
+ out.push({
40945
+ kind,
40946
+ handle,
40947
+ paragraph: block,
40948
+ blockIndex: input.rootBlockIndex,
40949
+ classifications: input.classificationIndex.get(markerScopeId) ?? Object.freeze([])
40950
+ });
40951
+ continue;
40952
+ }
40953
+ if (block.type === "sdt") {
40954
+ out.push(
40955
+ ...enumerateNestedMarkerBackedParagraphs(block.children, {
40956
+ ...input,
40957
+ semanticPrefix: [
40958
+ ...input.semanticPrefix,
40959
+ "sdt",
40960
+ String(childIndex)
40961
+ ]
40962
+ })
40963
+ );
40964
+ continue;
40965
+ }
40966
+ if (block.type === "table") {
40967
+ for (let rowIdx = 0; rowIdx < block.rows.length; rowIdx += 1) {
40968
+ const row = block.rows[rowIdx];
40969
+ for (let cellIdx = 0; cellIdx < row.cells.length; cellIdx += 1) {
40970
+ const cell = row.cells[cellIdx];
40971
+ out.push(
40972
+ ...enumerateNestedMarkerBackedParagraphs(cell.children, {
40973
+ ...input,
40974
+ semanticPrefix: [
40975
+ ...input.semanticPrefix,
40976
+ "table",
40977
+ String(childIndex),
40978
+ "row",
40979
+ String(rowIdx),
40980
+ "cell",
40981
+ String(cellIdx)
40982
+ ]
40983
+ })
40984
+ );
40985
+ }
40986
+ }
40987
+ }
40988
+ }
40989
+ return out;
40990
+ }
40904
40991
  function enumerateFieldsInParagraph(paragraph, blockIndex, documentId, parentScopeId) {
40905
40992
  const out = [];
40906
40993
  for (let i = 0; i < paragraph.children.length; i += 1) {
@@ -41183,6 +41270,17 @@ function enumerateScopes(document2, inputs = {}) {
41183
41270
  cellIndex: cellIdx,
41184
41271
  classifications: Object.freeze([])
41185
41272
  });
41273
+ for (const nested of enumerateNestedMarkerBackedParagraphs(cell.children, {
41274
+ documentId,
41275
+ rootBlockIndex: index,
41276
+ semanticPrefix: cellSemanticPath,
41277
+ parentScopeId: cellScopeId,
41278
+ knownOverlayScopeIds,
41279
+ classificationIndex,
41280
+ overlay: inputs.overlay
41281
+ })) {
41282
+ results.push(nested);
41283
+ }
41186
41284
  }
41187
41285
  }
41188
41286
  }
@@ -43381,9 +43479,7 @@ function applyScopeReplacement(inputs) {
43381
43479
  });
43382
43480
  if (!plan) {
43383
43481
  const paragraphLike = resolvedScope.kind === "paragraph" || resolvedScope.kind === "heading" || resolvedScope.kind === "list-item";
43384
- const blockers = resolvedScope.kind === "scope" && posture === "suggest-mode" ? [
43385
- proposed.proposedContent.kind === "structured" ? "compile-refused:scope:multi-paragraph-structured-suggesting-not-implemented" : "compile-refused:scope:multi-paragraph-suggesting-not-implemented"
43386
- ] : resolvedScope.kind === "scope" && proposed.operation !== "replace" ? [
43482
+ const blockers = resolvedScope.kind === "scope" && proposed.operation !== "replace" ? [
43387
43483
  `compile-refused:scope:operation-not-implemented:${proposed.operation}`
43388
43484
  ] : resolvedScope.kind === "scope" ? multiParagraphReplacementBlockers(
43389
43485
  proposed.proposedContent.kind === "structured" ? "fragment" : "text"
@@ -45044,6 +45140,7 @@ var PICTURE_EFFECT_SCHEME_ALIASES = {
45044
45140
  bg2: "lt2"
45045
45141
  };
45046
45142
  var EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH = /* @__PURE__ */ new Map();
45143
+ var NO_EDITABLE_TARGETS_INDEX = EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH;
45047
45144
  function indexEditableTargetsByBlockPath(document2) {
45048
45145
  const targets = collectEditableTargetRefs(document2);
45049
45146
  if (targets.length === 0) return EMPTY_EDITABLE_TARGETS_BY_BLOCK_PATH;
@@ -50037,7 +50134,8 @@ function buildResolvedSections(document2) {
50037
50134
  const mainSurface = createEditorSurfaceSnapshot(
50038
50135
  document2,
50039
50136
  createSelectionSnapshot(0, 0),
50040
- MAIN_STORY_TARGET
50137
+ MAIN_STORY_TARGET,
50138
+ { editableTargetsByBlockPath: NO_EDITABLE_TARGETS_INDEX }
50041
50139
  );
50042
50140
  const sections = [];
50043
50141
  let sectionStart = 0;
@@ -60856,6 +60954,216 @@ function createOutlineFamily(runtime) {
60856
60954
  };
60857
60955
  }
60858
60956
 
60957
+ // src/api/v3/ai/object.ts
60958
+ var applyObjectActionMetadata = {
60959
+ name: "ai.applyObjectAction",
60960
+ status: "live-with-adapter",
60961
+ sourceLayer: "runtime-core",
60962
+ liveEvidence: {
60963
+ runnerTest: "test/api/v3/ai/ai-object-actions.test.ts",
60964
+ commit: "refactor-09-object-actions"
60965
+ },
60966
+ uxIntent: {
60967
+ uiVisible: true,
60968
+ expectsUxResponse: "inline-change",
60969
+ expectedDelta: "image object layout changes"
60970
+ },
60971
+ agentMetadata: {
60972
+ readOrMutate: "mutate",
60973
+ boundedScope: "scope",
60974
+ auditCategory: "object-action-apply",
60975
+ contextPromptShape: "Apply an image object layout operation to an opaque actionHandle from ai.listObjectActions; preserve-only objects return typed blockers."
60976
+ },
60977
+ stateClass: "A-canonical",
60978
+ persistsTo: "canonical",
60979
+ broadcastsVia: "crdt",
60980
+ rwdReference: "\xA7AI API \xA7 ai.applyObjectAction"
60981
+ };
60982
+ function createObjectActionFamily(runtime) {
60983
+ const compiler = createScopeCompilerService(runtime);
60984
+ return {
60985
+ listObjectActions(input) {
60986
+ const bundle = compiler.compileBundleById(input.handle.scopeId, input.nowUtc);
60987
+ if (!bundle) {
60988
+ return {
60989
+ scopeId: input.handle.scopeId,
60990
+ actions: [],
60991
+ blockers: [`scope-not-resolvable:${input.handle.scopeId}`]
60992
+ };
60993
+ }
60994
+ const seed = documentSeed2(runtime);
60995
+ return {
60996
+ scopeId: input.handle.scopeId,
60997
+ actions: bundle.evidence.editableTargets?.entries.filter(isSupportedImageObjectEvidence).map((entry) => projectObjectDescriptor(runtime, seed, entry)) ?? []
60998
+ };
60999
+ },
61000
+ applyObjectAction(input) {
61001
+ emitUxResponse(runtime, {
61002
+ apiFn: applyObjectActionMetadata.name,
61003
+ intent: "object-action-apply",
61004
+ mockOrLive: applyObjectActionMetadata.status,
61005
+ uiVisible: true,
61006
+ expectedDelta: applyObjectActionMetadata.uxIntent.expectedDelta
61007
+ });
61008
+ const nowUtc = currentAuditTimestamp(runtime);
61009
+ const proposalId = input.proposalId ?? mockId(documentSeed2(runtime), `object-action-${input.actionHandle || "missing-handle"}-${input.operation.kind}`);
61010
+ if (!input.actionHandle) {
61011
+ return blockedResult2(input, proposalId, {
61012
+ code: "object-action-handle-required",
61013
+ category: "unresolved-target",
61014
+ message: "Object actions require an actionHandle from ai.listObjectActions.",
61015
+ nextStep: "Call ai.listObjectActions for the owning scope and retry with one returned actionHandle.",
61016
+ operation: input.operation.kind
61017
+ });
61018
+ }
61019
+ const target = resolveObjectActionHandle(runtime, documentSeed2(runtime), input.actionHandle);
61020
+ if (!target) {
61021
+ return blockedResult2(input, proposalId, {
61022
+ code: `object-action-handle-not-found:${input.actionHandle}`,
61023
+ category: "unresolved-target",
61024
+ message: "No current object action matches the supplied opaque action handle.",
61025
+ nextStep: "Refresh the scope bundle or call ai.listObjectActions before retrying.",
61026
+ actionHandle: input.actionHandle,
61027
+ operation: input.operation.kind
61028
+ });
61029
+ }
61030
+ if (!isSupportedImageTarget(target)) {
61031
+ return blockedResult2(input, proposalId, {
61032
+ code: "object-action-image-target-required",
61033
+ category: "blocked-target",
61034
+ message: "The supplied object action handle no longer identifies a mutable image target.",
61035
+ nextStep: "Refresh object actions; chart, OLE, custom XML, opaque, and stale object targets remain refused.",
61036
+ actionHandle: input.actionHandle,
61037
+ operation: input.operation.kind
61038
+ });
61039
+ }
61040
+ const mediaId = target.object?.mediaId;
61041
+ if (!mediaId) {
61042
+ return blockedResult2(input, proposalId, {
61043
+ code: "object-action-media-id-required",
61044
+ category: "blocked-target",
61045
+ message: "Image object layout mutation requires a mediaId-backed target.",
61046
+ nextStep: "Retry only with an image action handle whose readback includes mediaId.",
61047
+ actionHandle: input.actionHandle,
61048
+ operation: input.operation.kind
61049
+ });
61050
+ }
61051
+ const before = runtime.getCanonicalDocument();
61052
+ runtime.dispatch({
61053
+ type: "image.set-layout",
61054
+ mediaId,
61055
+ dimensions: {
61056
+ widthEmu: input.operation.dimensions.widthEmu,
61057
+ heightEmu: input.operation.dimensions.heightEmu
61058
+ },
61059
+ origin: { source: "api", timestamp: nowUtc }
61060
+ });
61061
+ const changed = runtime.getCanonicalDocument() !== before;
61062
+ if (!changed) {
61063
+ return blockedResult2(input, proposalId, {
61064
+ code: `object-action-noop:${input.operation.kind}:${input.actionHandle}`,
61065
+ category: "runtime-noop",
61066
+ message: "The runtime accepted the image target but the object operation produced no document change.",
61067
+ nextStep: "Refresh object actions and verify the image media item still exists before retrying.",
61068
+ actionHandle: input.actionHandle,
61069
+ operation: input.operation.kind
61070
+ });
61071
+ }
61072
+ return {
61073
+ proposalId,
61074
+ applied: true,
61075
+ changed: true,
61076
+ actionHandle: input.actionHandle,
61077
+ operation: input.operation.kind,
61078
+ commandReference: {
61079
+ command: "image.set-layout",
61080
+ actorId: input.actorId ?? "v3-ai-api",
61081
+ origin: input.origin ?? "agent",
61082
+ emittedAtUtc: nowUtc
61083
+ },
61084
+ readback: objectReadback(runtime, target),
61085
+ posture: "supported",
61086
+ support: objectActionSupport()
61087
+ };
61088
+ }
61089
+ };
61090
+ }
61091
+ function isSupportedImageObjectEvidence(entry) {
61092
+ return entry.kind === "object-anchor" && entry.commandFamily === "object" && entry.runtimeCommand.status === "supported" && entry.runtimeCommand.intents.includes("image-layout") && isImageKind(entry.object?.objectKind) && typeof entry.object?.mediaId === "string";
61093
+ }
61094
+ function projectObjectDescriptor(runtime, seed, entry) {
61095
+ return {
61096
+ actionHandle: objectActionHandle(seed, entry.targetKey),
61097
+ objectKind: entry.object?.objectKind ?? "unknown",
61098
+ targetKind: entry.kind,
61099
+ relation: entry.relation,
61100
+ callableOperations: ["set-image-layout"],
61101
+ supportedOperations: ["set-image-layout"],
61102
+ readback: objectReadback(runtime, entry),
61103
+ reason: entry.runtimeCommand.reason
61104
+ };
61105
+ }
61106
+ function resolveObjectActionHandle(runtime, seed, actionHandle) {
61107
+ return collectEditableTargetRefs(runtime.getCanonicalDocument()).find(
61108
+ (target) => objectActionHandle(seed, target.targetKey) === actionHandle && isSupportedImageTarget(target)
61109
+ ) ?? null;
61110
+ }
61111
+ function isSupportedImageTarget(target) {
61112
+ return target.kind === "object-anchor" && target.commandFamily === "object" && isImageKind(target.object?.objectKind) && typeof target.object?.mediaId === "string" && target.object.mediaId.length > 0 && onlyObjectActionBlockers(target.posture.blockers, ["unmodeled-target"]);
61113
+ }
61114
+ function isImageKind(kind) {
61115
+ return kind === "legacy-image" || kind === "picture";
61116
+ }
61117
+ function onlyObjectActionBlockers(blockers, allowed) {
61118
+ const allowedSet = new Set(allowed);
61119
+ return blockers.every((blocker2) => allowedSet.has(blocker2));
61120
+ }
61121
+ function objectReadback(runtime, target) {
61122
+ const mediaId = target.object?.mediaId;
61123
+ if (!mediaId) return {};
61124
+ const media = runtime.getCanonicalDocument().media.items[mediaId];
61125
+ return {
61126
+ mediaId,
61127
+ ...media?.widthEmu !== void 0 ? { widthEmu: media.widthEmu } : {},
61128
+ ...media?.heightEmu !== void 0 ? { heightEmu: media.heightEmu } : {}
61129
+ };
61130
+ }
61131
+ function blockedResult2(input, proposalId, detail) {
61132
+ return {
61133
+ proposalId,
61134
+ applied: false,
61135
+ changed: false,
61136
+ actionHandle: input.actionHandle,
61137
+ operation: input.operation.kind,
61138
+ reason: detail.code,
61139
+ blockers: [detail.code],
61140
+ blockerDetails: [detail]
61141
+ };
61142
+ }
61143
+ function objectActionSupport() {
61144
+ return {
61145
+ undo: "supported",
61146
+ replay: "supported",
61147
+ exportReopen: "supported",
61148
+ audit: "command-reference"
61149
+ };
61150
+ }
61151
+ function objectActionHandle(seed, targetKey) {
61152
+ return `object-action:${hashOpaque2(`${seed}::${targetKey}`)}`;
61153
+ }
61154
+ function documentSeed2(runtime) {
61155
+ const state = runtime.getSessionState();
61156
+ return state.documentId ?? "document";
61157
+ }
61158
+ function hashOpaque2(input) {
61159
+ let h = 2166136261;
61160
+ for (let i = 0; i < input.length; i += 1) {
61161
+ h ^= input.charCodeAt(i);
61162
+ h = Math.imul(h, 16777619);
61163
+ }
61164
+ return (h >>> 0).toString(36).padStart(7, "0");
61165
+ }
61166
+
60859
61167
  // src/api/v3/ai/actions.ts
60860
61168
  function actionMethodMetadata(method, readOrMutate, auditCategory, contextPromptShape, uxIntent) {
60861
61169
  return {
@@ -60900,6 +61208,17 @@ var locateAllMetadata = actionMethodMetadata(
60900
61208
  "Find scope/table-text targets by query; table text matches include readback {text,isEmpty}.",
60901
61209
  { uiVisible: false, expectsUxResponse: "none" }
60902
61210
  );
61211
+ var createPlaceholderScopesMetadata = actionMethodMetadata(
61212
+ "createPlaceholderScopes",
61213
+ "mutate",
61214
+ "actions-placeholder-scopes",
61215
+ "Create marker-backed workflow scopes for bracketed placeholder matches in paragraphs, tables, and lists using one bounded regex search.",
61216
+ {
61217
+ uiVisible: true,
61218
+ expectsUxResponse: "scope-created",
61219
+ expectedDelta: "placeholder text ranges become workflow scopes"
61220
+ }
61221
+ );
60903
61222
  var rewriteMetadata = actionMethodMetadata(
60904
61223
  "rewrite",
60905
61224
  "mutate",
@@ -61112,6 +61431,7 @@ var ACTION_METHODS = Object.freeze([
61112
61431
  "discover",
61113
61432
  "locate",
61114
61433
  "locateAll",
61434
+ "createPlaceholderScopes",
61115
61435
  "rewrite",
61116
61436
  "rewriteAll",
61117
61437
  "insertText",
@@ -61137,6 +61457,8 @@ var DEFAULT_LOCATE_LIMIT = 20;
61137
61457
  var DEFAULT_REWRITE_ALL_LIMIT = 10;
61138
61458
  var DEFAULT_TABLE_TEXT_SCOPE_LIMIT = 3;
61139
61459
  var DEFAULT_PLAN_STEP_LIMIT = 20;
61460
+ var DEFAULT_PLACEHOLDER_QUERY = "\\[[^\\[\\]]{1,200}\\]";
61461
+ var DEFAULT_PLACEHOLDER_LIMIT = 200;
61140
61462
  function createActionsFamily(runtime) {
61141
61463
  const category = {
61142
61464
  discover(input) {
@@ -61191,6 +61513,9 @@ function createActionsFamily(runtime) {
61191
61513
  locateAll(input) {
61192
61514
  return locateAll(runtime, input);
61193
61515
  },
61516
+ createPlaceholderScopes(input) {
61517
+ return createPlaceholderScopes(runtime, input ?? {});
61518
+ },
61194
61519
  rewrite(input) {
61195
61520
  if (input.text === void 0) {
61196
61521
  return blockedApply(
@@ -61959,6 +62284,169 @@ function locateAll(runtime, input) {
61959
62284
  ...matches.length === 0 ? { blockers: Object.freeze([`actions:locate:not-found:${input.query}`]) } : {}
61960
62285
  };
61961
62286
  }
62287
+ function createPlaceholderScopes(runtime, input) {
62288
+ const query = input.query ?? DEFAULT_PLACEHOLDER_QUERY;
62289
+ if (!query) {
62290
+ const detail = blocker(
62291
+ "actions:placeholder-scopes:query-required",
62292
+ "input",
62293
+ "Placeholder scope creation requires a non-empty query.",
62294
+ "Retry with a non-empty query string or omit query to use the bracketed-placeholder default."
62295
+ );
62296
+ return {
62297
+ status: "blocked",
62298
+ totalHits: 0,
62299
+ created: 0,
62300
+ blocked: 0,
62301
+ scopes: Object.freeze([]),
62302
+ blockers: Object.freeze([detail.code]),
62303
+ blockerDetails: Object.freeze([detail])
62304
+ };
62305
+ }
62306
+ const limit = Math.max(0, input.limit ?? DEFAULT_PLACEHOLDER_LIMIT);
62307
+ let hits;
62308
+ try {
62309
+ hits = runtime.findAllText(query, {
62310
+ regex: input.regex ?? true,
62311
+ matchCase: input.matchCase ?? true,
62312
+ limit
62313
+ });
62314
+ } catch {
62315
+ const detail = blocker(
62316
+ "actions:placeholder-scopes:invalid-query",
62317
+ "input",
62318
+ "The placeholder query could not be compiled or searched.",
62319
+ "Retry with a valid literal query or JavaScript regex pattern."
62320
+ );
62321
+ return {
62322
+ status: "blocked",
62323
+ totalHits: 0,
62324
+ created: 0,
62325
+ blocked: 0,
62326
+ scopes: Object.freeze([]),
62327
+ blockers: Object.freeze([detail.code]),
62328
+ blockerDetails: Object.freeze([detail])
62329
+ };
62330
+ }
62331
+ if (hits.length === 0) {
62332
+ return {
62333
+ status: "not-found",
62334
+ totalHits: 0,
62335
+ created: 0,
62336
+ blocked: 0,
62337
+ scopes: Object.freeze([]),
62338
+ blockers: Object.freeze([`actions:placeholder-scopes:not-found:${query}`])
62339
+ };
62340
+ }
62341
+ const surface = runtime.getRenderSnapshot().surface;
62342
+ const orderedHits = hits.filter((hit) => hit.kind === "range").map((hit, originalIndex) => ({
62343
+ hit,
62344
+ originalIndex,
62345
+ text: surface ? textForSurfaceRange(surface.blocks, hit.from, hit.to) : ""
62346
+ })).sort((a, b) => b.hit.from - a.hit.from || b.originalIndex - a.originalIndex);
62347
+ if (orderedHits.length === 0) {
62348
+ const detail = blocker(
62349
+ "actions:placeholder-scopes:no-range-hits",
62350
+ "unsupported",
62351
+ "The placeholder query matched only projections that cannot be converted into workflow ranges.",
62352
+ "Retry with a text query that resolves to concrete document text ranges."
62353
+ );
62354
+ return {
62355
+ status: "blocked",
62356
+ totalHits: hits.length,
62357
+ created: 0,
62358
+ blocked: hits.length,
62359
+ scopes: Object.freeze([]),
62360
+ blockers: Object.freeze([detail.code]),
62361
+ blockerDetails: Object.freeze([detail])
62362
+ };
62363
+ }
62364
+ const compiler = createScopeCompilerService(runtime);
62365
+ const byOriginalIndex = /* @__PURE__ */ new Map();
62366
+ for (const item of orderedHits) {
62367
+ const text = item.text || query;
62368
+ const label = input.labelPrefix === void 0 ? text : `${input.labelPrefix} ${item.originalIndex + 1}`;
62369
+ const result = createScopeFromAnchor(runtime, {
62370
+ anchor: { from: item.hit.from, to: item.hit.to },
62371
+ mode: input.mode ?? "edit",
62372
+ label,
62373
+ ...input.visibility ? { visibility: input.visibility } : {},
62374
+ ...input.guardPolicy ? { guardPolicy: input.guardPolicy } : {},
62375
+ ...input.assoc ? { assoc: input.assoc } : {},
62376
+ ...input.stableRefHint ? { stableRefHint: input.stableRefHint } : {}
62377
+ });
62378
+ if (result.status === "created") {
62379
+ const compiled = compiler.compileScopeById(result.scopeId)?.scope;
62380
+ byOriginalIndex.set(item.originalIndex, {
62381
+ status: "created",
62382
+ text,
62383
+ excerpt: excerpt(text),
62384
+ scopeId: result.scopeId,
62385
+ ...compiled?.handle ? { handle: compiled.handle } : {}
62386
+ });
62387
+ continue;
62388
+ }
62389
+ const detail = blockerWithOwner(
62390
+ `actions:placeholder-scopes:create-refused:${result.reason}`,
62391
+ "blocked",
62392
+ "The placeholder match could not be converted into a workflow scope.",
62393
+ "Refresh the document and retry; if it still refuses, route the target to the workflow/scope writer owner.",
62394
+ "L06"
62395
+ );
62396
+ byOriginalIndex.set(item.originalIndex, {
62397
+ status: "blocked",
62398
+ text,
62399
+ excerpt: excerpt(text),
62400
+ blockers: Object.freeze([detail.code]),
62401
+ blockerDetails: Object.freeze([detail])
62402
+ });
62403
+ }
62404
+ const scopes = orderedHits.map((item) => byOriginalIndex.get(item.originalIndex)).filter((value) => value !== void 0);
62405
+ const created = scopes.filter((scope) => scope.status === "created").length;
62406
+ const blocked2 = scopes.length - created;
62407
+ const blockerDetails = scopes.flatMap((scope) => scope.blockerDetails ?? []);
62408
+ return {
62409
+ status: created === scopes.length ? "created" : created > 0 ? "partial" : "blocked",
62410
+ totalHits: hits.length,
62411
+ created,
62412
+ blocked: blocked2,
62413
+ scopes: Object.freeze(scopes),
62414
+ ...blockerDetails.length > 0 ? {
62415
+ blockers: Object.freeze(blockerDetails.map((detail) => detail.code)),
62416
+ blockerDetails: Object.freeze(blockerDetails)
62417
+ } : {}
62418
+ };
62419
+ }
62420
+ function textForSurfaceRange(blocks, from, to) {
62421
+ let acc = "";
62422
+ const visit = (items) => {
62423
+ for (const block of items) {
62424
+ if (block.kind === "paragraph") {
62425
+ for (const segment of block.segments) {
62426
+ if (segment.kind !== "text") continue;
62427
+ if (segment.from >= to) return;
62428
+ if (segment.to <= from) continue;
62429
+ acc += segment.text.slice(
62430
+ Math.max(0, from - segment.from),
62431
+ Math.min(segment.text.length, to - segment.from)
62432
+ );
62433
+ }
62434
+ continue;
62435
+ }
62436
+ if (block.kind === "table") {
62437
+ for (const row of block.rows) {
62438
+ for (const cell of row.cells) visit(cell.content);
62439
+ }
62440
+ continue;
62441
+ }
62442
+ if (block.kind === "sdt_block") {
62443
+ visit(block.children);
62444
+ }
62445
+ }
62446
+ };
62447
+ visit(blocks);
62448
+ return acc;
62449
+ }
61962
62450
  function validateTemplateTargets(runtime, input) {
61963
62451
  if (!Array.isArray(input.targets) || input.targets.length === 0) {
61964
62452
  const detail = blocker(
@@ -62379,6 +62867,15 @@ function applyRewrite(runtime, target, input) {
62379
62867
  if (!listTextTarget.ok) return blockedApplyFromResolution(listTextTarget);
62380
62868
  return applyEditableTextRewrite(runtime, listTextTarget.target, input);
62381
62869
  }
62870
+ const tableTextTarget = uniqueTableTextActionForScope(runtime, target.handle);
62871
+ if (tableTextTarget.ok && tableTextTarget.action.readback?.text === target.scope.content.text) {
62872
+ return applyTableScopedMarkerRewrite(
62873
+ runtime,
62874
+ target,
62875
+ tableTextTarget.action,
62876
+ input
62877
+ );
62878
+ }
62382
62879
  const rewriteBlocker = scopeRewriteCapabilityBlocker(target.scope);
62383
62880
  if (rewriteBlocker) {
62384
62881
  return blockedApply(
@@ -62511,6 +63008,106 @@ function applyEditableTextRewrite(runtime, target, input) {
62511
63008
  afterReadback
62512
63009
  };
62513
63010
  }
63011
+ function applyTableScopedMarkerRewrite(runtime, target, action, input) {
63012
+ const workflowScope = runtime.getScope(target.handle.scopeId);
63013
+ const editableTarget = tableEditableTargetForActionHandle(
63014
+ runtime,
63015
+ action.actionHandle
63016
+ );
63017
+ if (!workflowScope || workflowScope.anchor.kind !== "range" || !editableTarget) {
63018
+ return blockedApply(
63019
+ `actions:rewrite:table-marker-target-unresolved:${target.handle.scopeId}`,
63020
+ "unresolved-target",
63021
+ "The table-contained marker scope could not be joined to a current table text target.",
63022
+ "Refresh placeholder scopes and retry; route persistent failures to L08 table scope target mapping."
63023
+ );
63024
+ }
63025
+ const before = runtime.getCanonicalDocument();
63026
+ try {
63027
+ runtime.dispatch({
63028
+ type: "selection.set",
63029
+ selection: {
63030
+ anchor: workflowScope.anchor.from,
63031
+ head: workflowScope.anchor.to,
63032
+ isCollapsed: workflowScope.anchor.from === workflowScope.anchor.to,
63033
+ activeRange: {
63034
+ kind: "range",
63035
+ from: workflowScope.anchor.from,
63036
+ to: workflowScope.anchor.to,
63037
+ assoc: workflowScope.anchor.assoc ?? { start: -1, end: 1 }
63038
+ }
63039
+ },
63040
+ origin: actionOrigin(runtime, input)
63041
+ });
63042
+ runtime.applyActiveStoryTextCommand({
63043
+ type: "text.insert",
63044
+ text: input.text,
63045
+ editableTarget,
63046
+ origin: actionOrigin(runtime, input)
63047
+ });
63048
+ } catch {
63049
+ return blockedApply(
63050
+ `actions:rewrite:table-marker-command-refused:${target.handle.scopeId}`,
63051
+ "blocked",
63052
+ "The table-contained marker scope could not be rewritten by the runtime text command.",
63053
+ "Retry with an exact table text actionHandle; route repeated failures to L07 table text command support.",
63054
+ [
63055
+ blockerWithOwner(
63056
+ `actions:rewrite:table-marker-command-refused:${target.handle.scopeId}`,
63057
+ "blocked",
63058
+ "The table-contained marker scope could not be rewritten by the runtime text command.",
63059
+ "Retry with an exact table text actionHandle; route repeated failures to L07 table text command support.",
63060
+ "L07 runtime text command support"
63061
+ )
63062
+ ]
63063
+ );
63064
+ }
63065
+ const changed = runtime.getCanonicalDocument() !== before;
63066
+ const paragraph = resolveParagraphTextTarget2(
63067
+ runtime.getCanonicalDocument(),
63068
+ editableTarget
63069
+ );
63070
+ const afterText = paragraph ? collectInlineText3(paragraph.children) : void 0;
63071
+ const afterReadback = afterText === void 0 ? void 0 : { text: afterText, isEmpty: afterText.length === 0 };
63072
+ if (!changed || afterReadback?.text !== input.text) {
63073
+ return {
63074
+ status: "blocked",
63075
+ applied: false,
63076
+ changed,
63077
+ target: summarizeTarget({ kind: "table-text", action }),
63078
+ posture: "suspect-readback",
63079
+ blockers: Object.freeze([
63080
+ `actions:rewrite:table-marker-readback-mismatch:${target.handle.scopeId}`
63081
+ ]),
63082
+ blockerDetails: Object.freeze([
63083
+ blocker(
63084
+ `actions:rewrite:table-marker-readback-mismatch:${target.handle.scopeId}`,
63085
+ "blocked",
63086
+ "The table-contained marker rewrite did not produce the requested exact table-cell readback.",
63087
+ "Treat the mutation as suspect. Re-read the target and export before claiming success."
63088
+ )
63089
+ ]),
63090
+ ...afterReadback ? { afterReadback } : {}
63091
+ };
63092
+ }
63093
+ return {
63094
+ status: "applied",
63095
+ applied: true,
63096
+ changed: true,
63097
+ target: summarizeTarget({
63098
+ kind: "table-text",
63099
+ action: { ...action, readback: afterReadback }
63100
+ }),
63101
+ commandReference: {
63102
+ command: "text.insert",
63103
+ actorId: input.actorId ?? "v3-ai-api",
63104
+ origin: input.origin ?? "agent",
63105
+ emittedAtUtc: currentAuditTimestamp(runtime)
63106
+ },
63107
+ ...action.readback ? { beforeReadback: action.readback } : {},
63108
+ afterReadback
63109
+ };
63110
+ }
62514
63111
  function projectRewriteScopeResult(runtime, result, target, beforeText, proposedText, documentMutated) {
62515
63112
  if (!result.applied) return projectApplyResult(result, target);
62516
63113
  const compiledAfter = createScopeCompilerService(runtime).compileScopeById(
@@ -62627,6 +63224,51 @@ function tableTextActionsForScope(runtime, handle) {
62627
63224
  });
62628
63225
  return result.actions.filter((action) => action.family === "table-text");
62629
63226
  }
63227
+ function uniqueTableTextActionForScope(runtime, handle) {
63228
+ const actions2 = tableTextActionsForScope(runtime, handle).filter(
63229
+ (action) => action.readback !== void 0
63230
+ );
63231
+ if (actions2.length === 1 && actions2[0]) {
63232
+ return { ok: true, action: actions2[0] };
63233
+ }
63234
+ if (actions2.length === 0) {
63235
+ return {
63236
+ ok: false,
63237
+ blockers: Object.freeze(["actions:rewrite:table-text-target-missing"]),
63238
+ blockerDetails: Object.freeze([
63239
+ blocker(
63240
+ "actions:rewrite:table-text-target-missing",
63241
+ "unsupported",
63242
+ "The scope does not expose a unique command-safe table text target.",
63243
+ "Use a paragraph/list scope, or retry with an exact table text actionHandle returned by ai.actions.locateAll."
63244
+ )
63245
+ ])
63246
+ };
63247
+ }
63248
+ return {
63249
+ ok: false,
63250
+ blockers: Object.freeze(["actions:rewrite:table-text-target-ambiguous"]),
63251
+ blockerDetails: Object.freeze([
63252
+ blocker(
63253
+ "actions:rewrite:table-text-target-ambiguous",
63254
+ "ambiguous-target",
63255
+ "The scope exposes multiple table text targets, so broad rewrite would be ambiguous.",
63256
+ "Retry with the exact table text actionHandle returned by ai.actions.locateAll or ai.listTableActions."
63257
+ )
63258
+ ])
63259
+ };
63260
+ }
63261
+ function tableEditableTargetForActionHandle(runtime, actionHandle) {
63262
+ for (const target of collectEditableTargetRefs(runtime.getCanonicalDocument())) {
63263
+ if (target.commandFamily !== "text-leaf" || target.table?.operationScope !== "text") {
63264
+ continue;
63265
+ }
63266
+ if (deriveTableActionHandleForTarget(runtime, target.targetKey) === actionHandle) {
63267
+ return target;
63268
+ }
63269
+ }
63270
+ return null;
63271
+ }
62630
63272
  function editableTextActionsForScope(runtime, handle) {
62631
63273
  const bundle = createScopeCompilerService(runtime).compileBundleById(
62632
63274
  handle.scopeId,
@@ -65080,7 +65722,7 @@ function createOverlaysFamily(ctx) {
65080
65722
  return {
65081
65723
  handle: {
65082
65724
  kind: "table-action",
65083
- id: tableActionHandle2(documentSeed2(), targetKey),
65725
+ id: tableActionHandle2(documentSeed3(), targetKey),
65084
65726
  targetKind,
65085
65727
  commandFamily,
65086
65728
  scope: tableActionScope(entry)
@@ -65104,9 +65746,9 @@ function createOverlaysFamily(ctx) {
65104
65746
  };
65105
65747
  }
65106
65748
  function tableActionHandle2(seed, targetKey) {
65107
- return `table-action:${hashOpaque2(`${seed}::${targetKey}`)}`;
65749
+ return `table-action:${hashOpaque3(`${seed}::${targetKey}`)}`;
65108
65750
  }
65109
- function hashOpaque2(input) {
65751
+ function hashOpaque3(input) {
65110
65752
  let h = 2166136261;
65111
65753
  for (let i = 0; i < input.length; i += 1) {
65112
65754
  h ^= input.charCodeAt(i);
@@ -65114,7 +65756,7 @@ function createOverlaysFamily(ctx) {
65114
65756
  }
65115
65757
  return (h >>> 0).toString(36).padStart(7, "0");
65116
65758
  }
65117
- function documentSeed2() {
65759
+ function documentSeed3() {
65118
65760
  return ctx.handle.getSessionState().documentId ?? "document";
65119
65761
  }
65120
65762
  function modeledTargetSourceIdentity(target) {
@@ -66443,6 +67085,7 @@ function createApiV3(handle, opts) {
66443
67085
  ...createStatsFamily(handle),
66444
67086
  ...createOutlineFamily(handle),
66445
67087
  ...createTableActionFamily(handle),
67088
+ ...createObjectActionFamily(handle),
66446
67089
  ...createActionsFamily(handle)
66447
67090
  };
66448
67091
  const runtime = {