@beyondwork/docx-react-component 1.0.106 → 1.0.109
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.
- package/package.json +19 -5
- package/src/api/geometry-overlay-rects.ts +5 -0
- package/src/api/package-version.ts +1 -1
- package/src/api/page-anchor-id.ts +5 -0
- package/src/api/public-types.ts +16 -9
- package/src/api/table-node-specs.ts +6 -0
- package/src/api/v3/_create.ts +2 -1
- package/src/api/v3/_page-anchor-id.ts +52 -0
- package/src/api/v3/_runtime-handle.ts +92 -1
- package/src/api/v3/ai/_audit-time.ts +5 -0
- package/src/api/v3/ai/_pe2-evidence.ts +38 -0
- package/src/api/v3/ai/attach.ts +7 -2
- package/src/api/v3/ai/replacement.ts +101 -18
- package/src/api/v3/ai/resolve.ts +2 -2
- package/src/api/v3/ai/review.ts +177 -3
- package/src/api/v3/index.ts +1 -0
- package/src/api/v3/runtime/collab.ts +462 -0
- package/src/api/v3/runtime/document.ts +503 -20
- package/src/api/v3/runtime/geometry.ts +97 -0
- package/src/api/v3/runtime/layout.ts +744 -0
- package/src/api/v3/runtime/perf-probe.ts +14 -0
- package/src/api/v3/runtime/viewport.ts +9 -8
- package/src/api/v3/ui/_types.ts +149 -55
- package/src/api/v3/ui/chrome-preset-model.ts +5 -5
- package/src/api/v3/ui/debug.ts +115 -2
- package/src/api/v3/ui/index.ts +13 -0
- package/src/api/v3/ui/overlays.ts +0 -8
- package/src/api/v3/ui/surface.ts +56 -0
- package/src/api/v3/ui/viewport.ts +22 -9
- package/src/core/commands/image-commands.ts +1 -0
- package/src/core/commands/index.ts +6 -0
- package/src/core/schema/text-schema.ts +43 -5
- package/src/core/selection/mapping.ts +8 -1
- package/src/core/selection/review-anchors.ts +5 -1
- package/src/core/state/text-transaction.ts +8 -2
- package/src/io/export/serialize-revisions.ts +149 -1
- package/src/io/normalize/normalize-text.ts +6 -0
- package/src/io/ooxml/parse-bookmark-references.ts +55 -0
- package/src/io/ooxml/parse-fields.ts +24 -2
- package/src/io/ooxml/parse-headers-footers.ts +38 -5
- package/src/io/ooxml/parse-main-document.ts +153 -9
- package/src/io/ooxml/parse-numbering.ts +20 -0
- package/src/io/ooxml/parse-revisions.ts +19 -8
- package/src/io/opc/package-reader.ts +98 -8
- package/src/model/anchor.ts +4 -3
- package/src/model/canonical-document.ts +220 -2
- package/src/model/canonical-hash.ts +221 -0
- package/src/model/canonical-layout-inputs.ts +245 -6
- package/src/model/layout/index.ts +1 -0
- package/src/model/layout/page-graph-types.ts +118 -1
- package/src/model/review/revision-types.ts +14 -3
- package/src/preservation/store.ts +20 -4
- package/src/review/README.md +1 -1
- package/src/review/store/revision-actions.ts +14 -2
- package/src/runtime/collab/event-types.ts +67 -1
- package/src/runtime/collab/runtime-collab-sync.ts +177 -5
- package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
- package/src/runtime/document-heading-outline.ts +147 -0
- package/src/runtime/document-navigation.ts +8 -243
- package/src/runtime/document-runtime.ts +240 -97
- package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
- package/src/runtime/formatting/layout-inputs.ts +38 -5
- package/src/runtime/formatting/numbering/geometry.ts +28 -2
- package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
- package/src/runtime/geometry/caret-geometry.ts +5 -6
- package/src/runtime/geometry/geometry-facet.ts +60 -10
- package/src/runtime/geometry/geometry-index.ts +591 -20
- package/src/runtime/geometry/geometry-types.ts +59 -0
- package/src/runtime/geometry/hit-test.ts +11 -1
- package/src/runtime/geometry/overlay-rects.ts +5 -3
- package/src/runtime/geometry/project-anchors.ts +1 -1
- package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
- package/src/runtime/layout/index.ts +6 -0
- package/src/runtime/layout/layout-engine-instance.ts +6 -1
- package/src/runtime/layout/layout-engine-version.ts +181 -16
- package/src/runtime/layout/layout-facet-types.ts +6 -0
- package/src/runtime/layout/page-graph.ts +21 -4
- package/src/runtime/layout/paginated-layout-engine.ts +139 -15
- package/src/runtime/layout/project-block-fragments.ts +265 -7
- package/src/runtime/layout/public-facet.ts +78 -24
- package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
- package/src/runtime/layout/table-row-split.ts +92 -35
- package/src/runtime/prerender/cache-envelope.ts +2 -2
- package/src/runtime/prerender/cache-key.ts +5 -4
- package/src/runtime/prerender/customxml-cache.ts +0 -1
- package/src/runtime/render/render-kernel.ts +1 -1
- package/src/runtime/revision-runtime.ts +112 -10
- package/src/runtime/scopes/_scope-dependencies.ts +1 -0
- package/src/runtime/scopes/action-validation.ts +22 -2
- package/src/runtime/scopes/capabilities.ts +316 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
- package/src/runtime/scopes/compiler-service.ts +108 -4
- package/src/runtime/scopes/content-control-evidence.ts +79 -0
- package/src/runtime/scopes/create-issue.ts +5 -5
- package/src/runtime/scopes/evidence.ts +91 -0
- package/src/runtime/scopes/formatting/apply.ts +2 -0
- package/src/runtime/scopes/geometry-evidence.ts +130 -0
- package/src/runtime/scopes/index.ts +54 -0
- package/src/runtime/scopes/issue-lifecycle.ts +224 -0
- package/src/runtime/scopes/layout-evidence.ts +374 -0
- package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
- package/src/runtime/scopes/preservation-boundary.ts +7 -1
- package/src/runtime/scopes/replacement/apply.ts +97 -34
- package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
- package/src/runtime/scopes/semantic-scope-types.ts +242 -3
- package/src/runtime/scopes/visualization.ts +28 -0
- package/src/runtime/surface-projection.ts +44 -5
- package/src/runtime/telemetry/perf-probe.ts +216 -0
- package/src/runtime/virtualized-rendering.ts +36 -1
- package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
- package/src/runtime/workflow/coordinator.ts +39 -11
- package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
- package/src/runtime/workflow/index.ts +3 -0
- package/src/runtime/workflow/overlay-lane-types.ts +58 -0
- package/src/runtime/workflow/overlay-lanes.ts +168 -10
- package/src/runtime/workflow/overlay-store.ts +2 -2
- package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
- package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
- package/src/session/_sync-legacy.ts +17 -27
- package/src/session/import/loader.ts +6 -4
- package/src/session/import/source-package-evidence.ts +186 -2
- package/src/session/index.ts +5 -6
- package/src/session/session.ts +30 -56
- package/src/session/types.ts +8 -13
- package/src/shell/session-bootstrap.ts +155 -81
- package/src/ui/WordReviewEditor.tsx +520 -12
- package/src/ui/editor-shell-view.tsx +14 -4
- package/src/ui/editor-surface-controller.tsx +5 -3
- package/src/ui/headless/selection-tool-resolver.ts +1 -2
- package/src/ui/presence-overlay-lane.ts +0 -1
- package/src/ui/ui-controller-factory.ts +7 -0
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
- package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
- package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
- package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
- package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
- package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
- package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
- package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
- package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
- package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
- package/src/ui-tailwind/debug/README.md +4 -1
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
- package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
- package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
- package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
- package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
- package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
- package/src/ui-tailwind/review-workspace/types.ts +26 -12
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
- package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
- package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
|
@@ -128,6 +128,55 @@ function longestTextOnlyRangeInParagraph(
|
|
|
128
128
|
return best;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
function textInParagraphRange(
|
|
132
|
+
paragraph: ParagraphLikeEnumeratedScope["paragraph"],
|
|
133
|
+
paragraphFrom: number,
|
|
134
|
+
target: { readonly from: number; readonly to: number },
|
|
135
|
+
): string {
|
|
136
|
+
let cursor = paragraphFrom;
|
|
137
|
+
const parts: string[] = [];
|
|
138
|
+
|
|
139
|
+
const appendText = (text: string, from: number, to: number) => {
|
|
140
|
+
const clippedFrom = Math.max(from, target.from);
|
|
141
|
+
const clippedTo = Math.min(to, target.to);
|
|
142
|
+
if (clippedTo <= clippedFrom) return;
|
|
143
|
+
const localFrom = clippedFrom - from;
|
|
144
|
+
const localTo = clippedTo - from;
|
|
145
|
+
parts.push(Array.from(text).slice(localFrom, localTo).join(""));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const walkInline = (node: InlineNode, from: number): number => {
|
|
149
|
+
switch (node.type) {
|
|
150
|
+
case "text": {
|
|
151
|
+
const chars = Array.from(node.text);
|
|
152
|
+
appendText(node.text, from, from + chars.length);
|
|
153
|
+
return chars.length;
|
|
154
|
+
}
|
|
155
|
+
case "tab":
|
|
156
|
+
appendText("\t", from, from + 1);
|
|
157
|
+
return 1;
|
|
158
|
+
case "hard_break":
|
|
159
|
+
appendText("\n", from, from + 1);
|
|
160
|
+
return 1;
|
|
161
|
+
case "hyperlink":
|
|
162
|
+
case "field": {
|
|
163
|
+
let local = from;
|
|
164
|
+
for (const child of node.children as readonly InlineNode[]) {
|
|
165
|
+
local += walkInline(child, local);
|
|
166
|
+
}
|
|
167
|
+
return local - from;
|
|
168
|
+
}
|
|
169
|
+
default:
|
|
170
|
+
return inlineLengthLocal(node);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
for (const child of paragraph.children) {
|
|
175
|
+
cursor += walkInline(child, cursor);
|
|
176
|
+
}
|
|
177
|
+
return parts.join("");
|
|
178
|
+
}
|
|
179
|
+
|
|
131
180
|
export interface CompileParagraphOptions {
|
|
132
181
|
readonly document?: CanonicalDocument;
|
|
133
182
|
readonly paragraphIndex?: number;
|
|
@@ -198,13 +247,17 @@ export interface CompileParagraphReplacementOptions {
|
|
|
198
247
|
* Slice 5 — lower a paragraph-scope replacement proposal into a
|
|
199
248
|
* `RuntimeOperationPlan`. Handles two content kinds:
|
|
200
249
|
*
|
|
201
|
-
* - `kind: "text"` → single `text-replace` step spanning
|
|
202
|
-
* paragraph's
|
|
203
|
-
* the existing `text.insert` runtime command.
|
|
250
|
+
* - `replace` + `kind: "text"` → single `text-replace` step spanning
|
|
251
|
+
* the paragraph's effective scope range; passes a flat string
|
|
252
|
+
* through the existing `text.insert` runtime command.
|
|
253
|
+
* - `insert-before` / `insert-after` + `kind: "text"` → single
|
|
254
|
+
* collapsed `text-replace` (or tracked insert in suggest mode) at
|
|
255
|
+
* the effective scope edge.
|
|
204
256
|
* - `kind: "structured"` → single `fragment-replace` step carrying
|
|
205
257
|
* a `CanonicalDocumentFragment` payload; dispatches via the
|
|
206
|
-
* runtime's `insertFragment` pipeline with the
|
|
207
|
-
* selection
|
|
258
|
+
* runtime's `insertFragment` pipeline with the effective range as
|
|
259
|
+
* selection for replace, or a collapsed edge for insert-before /
|
|
260
|
+
* insert-after. Unblocked 2026-04-22 once L02 shipped
|
|
208
261
|
* `CanonicalDocumentFragment` (`src/model/canonical-document.ts`).
|
|
209
262
|
*
|
|
210
263
|
* Determinism (S3): the plan is a pure projection of (blockIndex,
|
|
@@ -215,7 +268,13 @@ export function compileParagraphReplacement(
|
|
|
215
268
|
proposed: ReplacementScope,
|
|
216
269
|
options: CompileParagraphReplacementOptions,
|
|
217
270
|
): RuntimeOperationPlan | null {
|
|
218
|
-
if (
|
|
271
|
+
if (
|
|
272
|
+
proposed.operation !== "replace" &&
|
|
273
|
+
proposed.operation !== "insert-before" &&
|
|
274
|
+
proposed.operation !== "insert-after"
|
|
275
|
+
) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
219
278
|
|
|
220
279
|
const blocks = computeBlockPositions(options.document);
|
|
221
280
|
const blockRange = blocks.find((b) => b.blockIndex === entry.blockIndex);
|
|
@@ -259,7 +318,10 @@ export function compileParagraphReplacement(
|
|
|
259
318
|
// replace range to the longest contiguous text-only sub-range so
|
|
260
319
|
// opaque inlines (images, charts, preserve-only fragments) survive
|
|
261
320
|
// the apply at their original positions.
|
|
262
|
-
if (
|
|
321
|
+
if (
|
|
322
|
+
proposed.operation === "replace" &&
|
|
323
|
+
proposed.preserve?.opaqueFragments === true
|
|
324
|
+
) {
|
|
263
325
|
const textOnly = longestTextOnlyRangeInParagraph(
|
|
264
326
|
entry.paragraph,
|
|
265
327
|
blockRange.from,
|
|
@@ -276,8 +338,22 @@ export function compileParagraphReplacement(
|
|
|
276
338
|
rangeKind = "opaque-preserving-text";
|
|
277
339
|
}
|
|
278
340
|
|
|
341
|
+
const operationRange =
|
|
342
|
+
proposed.operation === "insert-before"
|
|
343
|
+
? { from: effectiveRange.from, to: effectiveRange.from }
|
|
344
|
+
: proposed.operation === "insert-after"
|
|
345
|
+
? { from: effectiveRange.to, to: effectiveRange.to }
|
|
346
|
+
: effectiveRange;
|
|
347
|
+
|
|
279
348
|
if (proposed.proposedContent.kind === "text") {
|
|
280
349
|
const text = proposed.proposedContent.text ?? "";
|
|
350
|
+
if (
|
|
351
|
+
proposed.operation === "replace" &&
|
|
352
|
+
proposed.preserve?.opaqueFragments === true &&
|
|
353
|
+
textInParagraphRange(entry.paragraph, blockRange.from, operationRange) === text
|
|
354
|
+
) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
281
357
|
const stepKind =
|
|
282
358
|
options.posture === "suggest-mode" ? "text-insert-tracked" : "text-replace";
|
|
283
359
|
const summaryScope =
|
|
@@ -286,6 +362,16 @@ export function compileParagraphReplacement(
|
|
|
286
362
|
: rangeKind === "opaque-preserving-text"
|
|
287
363
|
? `paragraph #${entry.blockIndex} opaque-preserving text range [${effectiveRange.from}..${effectiveRange.to}]`
|
|
288
364
|
: `paragraph #${entry.blockIndex}`;
|
|
365
|
+
const actionVerb =
|
|
366
|
+
proposed.operation === "insert-before"
|
|
367
|
+
? "insert before"
|
|
368
|
+
: proposed.operation === "insert-after"
|
|
369
|
+
? "insert after"
|
|
370
|
+
: "replace";
|
|
371
|
+
const actionSummary =
|
|
372
|
+
proposed.operation === "replace"
|
|
373
|
+
? `${actionVerb} ${summaryScope} text (len ${text.length})`
|
|
374
|
+
: `${actionVerb} ${summaryScope} text at ${operationRange.from} (len ${text.length})`;
|
|
289
375
|
return {
|
|
290
376
|
scopeId: entry.handle.scopeId,
|
|
291
377
|
targetKind: "paragraph",
|
|
@@ -295,9 +381,9 @@ export function compileParagraphReplacement(
|
|
|
295
381
|
kind: stepKind,
|
|
296
382
|
summary:
|
|
297
383
|
stepKind === "text-replace"
|
|
298
|
-
?
|
|
299
|
-
: `suggest-mode ${
|
|
300
|
-
range: { from:
|
|
384
|
+
? actionSummary
|
|
385
|
+
: `suggest-mode ${actionSummary}`,
|
|
386
|
+
range: { from: operationRange.from, to: operationRange.to },
|
|
301
387
|
text,
|
|
302
388
|
...(proposed.formatting ? { formatting: proposed.formatting } : {}),
|
|
303
389
|
},
|
|
@@ -325,6 +411,16 @@ export function compileParagraphReplacement(
|
|
|
325
411
|
: rangeKind === "opaque-preserving-text"
|
|
326
412
|
? `paragraph #${entry.blockIndex} opaque-preserving text range [${effectiveRange.from}..${effectiveRange.to}]`
|
|
327
413
|
: `paragraph #${entry.blockIndex}`;
|
|
414
|
+
const actionVerb =
|
|
415
|
+
proposed.operation === "insert-before"
|
|
416
|
+
? "insert before"
|
|
417
|
+
: proposed.operation === "insert-after"
|
|
418
|
+
? "insert after"
|
|
419
|
+
: "replace";
|
|
420
|
+
const actionSummary =
|
|
421
|
+
proposed.operation === "replace"
|
|
422
|
+
? `${actionVerb} ${summaryScope} with structured fragment (${blockCount} block(s))`
|
|
423
|
+
: `${actionVerb} ${summaryScope} structured fragment at ${operationRange.from} (${blockCount} block(s))`;
|
|
328
424
|
return {
|
|
329
425
|
scopeId: entry.handle.scopeId,
|
|
330
426
|
targetKind: "paragraph",
|
|
@@ -332,8 +428,8 @@ export function compileParagraphReplacement(
|
|
|
332
428
|
steps: Object.freeze([
|
|
333
429
|
{
|
|
334
430
|
kind: "fragment-replace",
|
|
335
|
-
summary:
|
|
336
|
-
range: { from:
|
|
431
|
+
summary: actionSummary,
|
|
432
|
+
range: { from: operationRange.from, to: operationRange.to },
|
|
337
433
|
fragment,
|
|
338
434
|
},
|
|
339
435
|
]),
|
|
@@ -257,6 +257,19 @@ export interface AIIssueSummary {
|
|
|
257
257
|
readonly severity: "info" | "warning" | "error";
|
|
258
258
|
readonly status: "open" | "resolved";
|
|
259
259
|
readonly createdAtUtc?: string;
|
|
260
|
+
readonly statusUpdatedAtUtc?: string;
|
|
261
|
+
readonly resolvedAtUtc?: string;
|
|
262
|
+
readonly resolvedBy?: string;
|
|
263
|
+
readonly reopenedAtUtc?: string;
|
|
264
|
+
readonly reopenedBy?: string;
|
|
265
|
+
readonly lastTransition?: {
|
|
266
|
+
readonly action: "resolve" | "reopen";
|
|
267
|
+
readonly actorId: string;
|
|
268
|
+
readonly at: string;
|
|
269
|
+
readonly origin: string;
|
|
270
|
+
readonly fromStatus: "open" | "resolved";
|
|
271
|
+
readonly toStatus: "open" | "resolved";
|
|
272
|
+
};
|
|
260
273
|
}
|
|
261
274
|
|
|
262
275
|
export interface ScopeBundleEvidence {
|
|
@@ -264,6 +277,37 @@ export interface ScopeBundleEvidence {
|
|
|
264
277
|
readonly reviewItemIds?: readonly string[];
|
|
265
278
|
readonly overlappingWorkflowScopeIds?: readonly string[];
|
|
266
279
|
readonly compatibilityFlags?: readonly string[];
|
|
280
|
+
/**
|
|
281
|
+
* Layout evidence projected from L04/L05 join surfaces when present.
|
|
282
|
+
* Missing layout truth is represented explicitly; Layer 08 does not infer
|
|
283
|
+
* page slices, continuation, or divergence rows from content or DOM state.
|
|
284
|
+
*/
|
|
285
|
+
readonly layout?: ScopeLayoutEvidence;
|
|
286
|
+
/**
|
|
287
|
+
* Geometry envelope evidence projected from Layer 05 when a geometry facet
|
|
288
|
+
* is wired. Missing/cold geometry is represented explicitly as
|
|
289
|
+
* `requires-rehydration` or `unavailable`; Layer 08 never fabricates rects.
|
|
290
|
+
*/
|
|
291
|
+
readonly geometry?: ScopeGeometryEvidence;
|
|
292
|
+
/**
|
|
293
|
+
* Presentation hint only. Consumers may use this to choose a cheap inline
|
|
294
|
+
* treatment for field-like scopes versus a broader overlay treatment for
|
|
295
|
+
* everything else, but it is not layout or geometry authority.
|
|
296
|
+
*/
|
|
297
|
+
readonly visualization?: ScopeVisualizationHint;
|
|
298
|
+
/**
|
|
299
|
+
* Current action capability verdicts for this scope. These are evidence
|
|
300
|
+
* only: they explain what the shipped compiler/runtime can lower today
|
|
301
|
+
* without broadening the mutation surface.
|
|
302
|
+
*/
|
|
303
|
+
readonly capabilities?: ScopeCapabilities;
|
|
304
|
+
/**
|
|
305
|
+
* Content-control / SDT overlap evidence. These are preserve-first wrapper
|
|
306
|
+
* facts: when present on a target scope, replacement capability verdicts and
|
|
307
|
+
* validation must surface blockers instead of treating the wrapper like
|
|
308
|
+
* ordinary editable text.
|
|
309
|
+
*/
|
|
310
|
+
readonly contentControls?: ScopeContentControlEvidence;
|
|
267
311
|
/**
|
|
268
312
|
* Agent-authored explanations on this scope, read back from Layer-06
|
|
269
313
|
* metadata entries keyed by `metadataId: "ai.explanation"`. Adversarial-
|
|
@@ -279,6 +323,192 @@ export interface ScopeBundleEvidence {
|
|
|
279
323
|
readonly aiIssues?: readonly AIIssueSummary[];
|
|
280
324
|
}
|
|
281
325
|
|
|
326
|
+
export type ScopeEvidenceAvailability =
|
|
327
|
+
| "available"
|
|
328
|
+
| "partial"
|
|
329
|
+
| "degraded"
|
|
330
|
+
| "requires-rehydration"
|
|
331
|
+
| "unavailable";
|
|
332
|
+
|
|
333
|
+
export interface ScopeLayoutContinuationEvidence {
|
|
334
|
+
readonly pageIds?: readonly string[];
|
|
335
|
+
readonly pageCount?: number;
|
|
336
|
+
readonly crossesPageBoundary?: boolean;
|
|
337
|
+
readonly continuedFromPreviousPage?: boolean;
|
|
338
|
+
readonly continuesToNextPage?: boolean;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface ScopeTableFramePageEvidence {
|
|
342
|
+
readonly pageId: string;
|
|
343
|
+
readonly pageIndex: number;
|
|
344
|
+
readonly fragmentId: string;
|
|
345
|
+
readonly rowRange?: {
|
|
346
|
+
readonly from: number;
|
|
347
|
+
readonly to: number;
|
|
348
|
+
readonly totalRows: number;
|
|
349
|
+
};
|
|
350
|
+
readonly continuesFromPreviousPage?: boolean;
|
|
351
|
+
readonly continuesToNextPage?: boolean;
|
|
352
|
+
readonly repeatedHeaderRowIndexes?: readonly number[];
|
|
353
|
+
readonly splitRowCarry?: readonly {
|
|
354
|
+
readonly rowIndex: number;
|
|
355
|
+
readonly continuesFromPreviousPage: boolean;
|
|
356
|
+
readonly continuesToNextPage: boolean;
|
|
357
|
+
}[];
|
|
358
|
+
readonly verticalMergeCarry?: readonly {
|
|
359
|
+
readonly columnIndex: number;
|
|
360
|
+
readonly restartRowIndex: number;
|
|
361
|
+
}[];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export interface ScopeTableFrameEvidence {
|
|
365
|
+
readonly source: "runtime.layout.table-frame-continuation";
|
|
366
|
+
readonly blockId: string;
|
|
367
|
+
readonly scopeKind: "table" | "table-row" | "table-cell";
|
|
368
|
+
readonly rowIndex?: number;
|
|
369
|
+
readonly cellIndex?: number;
|
|
370
|
+
readonly pageIds?: readonly string[];
|
|
371
|
+
readonly pageSliceIds?: readonly string[];
|
|
372
|
+
readonly layoutObjectIds?: readonly string[];
|
|
373
|
+
readonly rowRangesByPage?: readonly ScopeTableFramePageEvidence[];
|
|
374
|
+
readonly repeatedHeaderRowIndexes?: readonly number[];
|
|
375
|
+
readonly splitRowCarry?: readonly {
|
|
376
|
+
readonly rowIndex: number;
|
|
377
|
+
readonly continuesFromPreviousPage: boolean;
|
|
378
|
+
readonly continuesToNextPage: boolean;
|
|
379
|
+
}[];
|
|
380
|
+
readonly verticalMergeCarry?: readonly {
|
|
381
|
+
readonly columnIndex: number;
|
|
382
|
+
readonly restartRowIndex: number;
|
|
383
|
+
}[];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export interface ScopeLayoutEvidence {
|
|
387
|
+
readonly status: ScopeEvidenceAvailability;
|
|
388
|
+
readonly completeness:
|
|
389
|
+
| "complete"
|
|
390
|
+
| "partial"
|
|
391
|
+
| "degraded"
|
|
392
|
+
| "requires-rehydration"
|
|
393
|
+
| "unavailable";
|
|
394
|
+
readonly reason?: string;
|
|
395
|
+
readonly pageSliceIds?: readonly string[];
|
|
396
|
+
readonly layoutObjectIds?: readonly string[];
|
|
397
|
+
readonly continuationState?: ScopeLayoutContinuationEvidence;
|
|
398
|
+
readonly divergenceIds?: readonly string[];
|
|
399
|
+
readonly tableFrame?: ScopeTableFrameEvidence;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export type ScopeGeometryEvidenceStatus =
|
|
403
|
+
| "available"
|
|
404
|
+
| "requires-rehydration"
|
|
405
|
+
| "unavailable";
|
|
406
|
+
|
|
407
|
+
export type ScopeGeometryEvidencePrecision =
|
|
408
|
+
| "exact"
|
|
409
|
+
| "within-tolerance"
|
|
410
|
+
| "heuristic";
|
|
411
|
+
|
|
412
|
+
export interface ScopeGeometryEvidenceRect {
|
|
413
|
+
readonly x: number;
|
|
414
|
+
readonly y: number;
|
|
415
|
+
readonly width: number;
|
|
416
|
+
readonly height: number;
|
|
417
|
+
readonly space: "twips" | "frame" | "overlay";
|
|
418
|
+
readonly precision?: ScopeGeometryEvidencePrecision;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export interface ScopeGeometryEvidence {
|
|
422
|
+
readonly status: ScopeGeometryEvidenceStatus;
|
|
423
|
+
readonly requiresRehydration: boolean;
|
|
424
|
+
readonly reason?: string;
|
|
425
|
+
readonly pageIds?: readonly string[];
|
|
426
|
+
readonly confidence?: "exact" | "medium" | "detached";
|
|
427
|
+
readonly precision?: ScopeGeometryEvidencePrecision;
|
|
428
|
+
readonly rects?: readonly ScopeGeometryEvidenceRect[];
|
|
429
|
+
readonly attachPoint?: {
|
|
430
|
+
readonly x: number;
|
|
431
|
+
readonly y: number;
|
|
432
|
+
readonly space: "twips" | "frame" | "overlay";
|
|
433
|
+
};
|
|
434
|
+
readonly linesCrossed?: number;
|
|
435
|
+
readonly continuationState?: ScopeLayoutContinuationEvidence;
|
|
436
|
+
readonly sourceIdentity?: {
|
|
437
|
+
readonly storyKey?: string;
|
|
438
|
+
readonly blockPath?: string;
|
|
439
|
+
readonly tableKey?: string;
|
|
440
|
+
readonly rowKey?: string;
|
|
441
|
+
readonly cellKey?: string;
|
|
442
|
+
readonly scopeKey?: string;
|
|
443
|
+
readonly scopeId?: string;
|
|
444
|
+
readonly objectKey?: string;
|
|
445
|
+
readonly inlinePath?: string;
|
|
446
|
+
readonly objectKind?: string;
|
|
447
|
+
readonly editPosture?: string;
|
|
448
|
+
readonly joinKind?: string;
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export type ScopeVisualizationClass = "field" | "broad";
|
|
453
|
+
|
|
454
|
+
export interface ScopeVisualizationHint {
|
|
455
|
+
readonly class: ScopeVisualizationClass;
|
|
456
|
+
readonly reason: string;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export type ScopeCapabilityStatus =
|
|
460
|
+
| "supported"
|
|
461
|
+
| "blocked"
|
|
462
|
+
| "unsupported"
|
|
463
|
+
| "degraded";
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Action posture for compiler consumers that need to distinguish "warn and
|
|
467
|
+
* proceed" from a real refusal. L08 must prefer `warn-and-proceed` whenever
|
|
468
|
+
* the mutation can be lowered without losing preserved truth or fabricating
|
|
469
|
+
* layout/geometry. `hard-refusal` means the action must not dispatch.
|
|
470
|
+
*/
|
|
471
|
+
export type ScopeActionPosture =
|
|
472
|
+
| "supported"
|
|
473
|
+
| "warn-and-proceed"
|
|
474
|
+
| "hard-refusal";
|
|
475
|
+
|
|
476
|
+
export interface ScopeCapabilityVerdict {
|
|
477
|
+
readonly supported: boolean;
|
|
478
|
+
readonly status: ScopeCapabilityStatus;
|
|
479
|
+
readonly posture?: ScopeActionPosture;
|
|
480
|
+
readonly reason?: string;
|
|
481
|
+
readonly blockers?: readonly string[];
|
|
482
|
+
readonly warnings?: readonly string[];
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export interface ScopeCapabilities {
|
|
486
|
+
readonly canReplaceText: ScopeCapabilityVerdict;
|
|
487
|
+
readonly canReplaceFragment: ScopeCapabilityVerdict;
|
|
488
|
+
readonly canInsertBefore: ScopeCapabilityVerdict;
|
|
489
|
+
readonly canInsertAfter: ScopeCapabilityVerdict;
|
|
490
|
+
readonly canApplyFormatting: ScopeCapabilityVerdict;
|
|
491
|
+
readonly canClearFormattingLayer: ScopeCapabilityVerdict;
|
|
492
|
+
readonly canAttachMetadata: ScopeCapabilityVerdict;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export type ScopeContentControlEvidenceStatus = "none" | "present";
|
|
496
|
+
|
|
497
|
+
export interface ScopeContentControlEvidenceEntry {
|
|
498
|
+
readonly evidenceId: string;
|
|
499
|
+
readonly blockIndex: number;
|
|
500
|
+
readonly sdtType?: string;
|
|
501
|
+
readonly alias?: string;
|
|
502
|
+
readonly tag?: string;
|
|
503
|
+
readonly lock?: string;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export interface ScopeContentControlEvidence {
|
|
507
|
+
readonly status: ScopeContentControlEvidenceStatus;
|
|
508
|
+
readonly count: number;
|
|
509
|
+
readonly entries: readonly ScopeContentControlEvidenceEntry[];
|
|
510
|
+
}
|
|
511
|
+
|
|
282
512
|
export interface ScopeBundle {
|
|
283
513
|
readonly scope: SemanticScope;
|
|
284
514
|
readonly neighborhood: ScopeBundleNeighborhood;
|
|
@@ -286,11 +516,19 @@ export interface ScopeBundle {
|
|
|
286
516
|
readonly generatedAtUtc: string;
|
|
287
517
|
}
|
|
288
518
|
|
|
289
|
-
export type
|
|
519
|
+
export type ScopeReplacementOperationKind =
|
|
290
520
|
| "replace"
|
|
291
521
|
| "insert-before"
|
|
292
|
-
| "insert-after"
|
|
293
|
-
|
|
522
|
+
| "insert-after";
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Compiler-internal proposal operation. Public replacement surfaces accept
|
|
526
|
+
* `ScopeReplacementOperationKind`; `annotate` is retained only for metadata
|
|
527
|
+
* write audit records (`ai.attachExplanation` / `ai.createIssue`) that reuse
|
|
528
|
+
* the `ScopeActionAudit` shape without going through text replacement.
|
|
529
|
+
*/
|
|
530
|
+
export type ReplacementOperationKind =
|
|
531
|
+
| ScopeReplacementOperationKind
|
|
294
532
|
| "annotate";
|
|
295
533
|
|
|
296
534
|
export interface ReplacementPreservePolicy {
|
|
@@ -426,6 +664,7 @@ export interface ValidationApproval {
|
|
|
426
664
|
*/
|
|
427
665
|
export interface ValidationResult {
|
|
428
666
|
readonly safe: boolean;
|
|
667
|
+
readonly posture?: ScopeActionPosture;
|
|
429
668
|
readonly blockedReasons: readonly string[];
|
|
430
669
|
readonly warnings: readonly ValidationIssue[];
|
|
431
670
|
readonly approval?: ValidationApproval;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope visualization hint projection.
|
|
3
|
+
*
|
|
4
|
+
* This is deliberately evidence, not geometry. Layer 08 can tell consumers
|
|
5
|
+
* whether a scope is structurally field-like or broad; Layer 05 remains the
|
|
6
|
+
* authority for rects, line spans, and overlay envelopes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
ScopeVisualizationHint,
|
|
11
|
+
SemanticScope,
|
|
12
|
+
} from "./semantic-scope-types.ts";
|
|
13
|
+
|
|
14
|
+
export function deriveScopeVisualization(
|
|
15
|
+
scope: SemanticScope,
|
|
16
|
+
): ScopeVisualizationHint {
|
|
17
|
+
if (scope.kind === "field") {
|
|
18
|
+
return {
|
|
19
|
+
class: "field",
|
|
20
|
+
reason: "kind:field",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
class: "broad",
|
|
26
|
+
reason: `kind:${scope.kind}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -149,7 +149,7 @@ export interface SurfaceProjectionOptions {
|
|
|
149
149
|
* if you call `createEditorSurfaceSnapshot` directly, normalize first.
|
|
150
150
|
*/
|
|
151
151
|
viewportBlockRanges?: readonly { start: number; end: number }[] | null;
|
|
152
|
-
/** @deprecated use `viewportBlockRanges`. Kept for back-compat;
|
|
152
|
+
/** @deprecated use `viewportBlockRanges`. Kept for back-compat; remove after the next published API pin refresh. */
|
|
153
153
|
viewportBlockRange?: { start: number; end: number } | null;
|
|
154
154
|
/**
|
|
155
155
|
* Active markup mode. When set together with the document's
|
|
@@ -444,7 +444,9 @@ function createSurfaceBlock(
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
if (block.type === "sdt") {
|
|
447
|
-
const descriptor = describeStructuredWrapperBlock(block
|
|
447
|
+
const descriptor = describeStructuredWrapperBlock(block, {
|
|
448
|
+
projectVisibleTocContentControls: true,
|
|
449
|
+
});
|
|
448
450
|
if (descriptor) {
|
|
449
451
|
const blockId = `sdt-wrapper-${counters.sdt}`;
|
|
450
452
|
counters.sdt += 1;
|
|
@@ -1086,6 +1088,12 @@ function createSdtBlock(
|
|
|
1086
1088
|
const children: SurfaceBlockSnapshot[] = [];
|
|
1087
1089
|
const lockedFragmentIds: string[] = [];
|
|
1088
1090
|
let innerCursor = cursor;
|
|
1091
|
+
const descriptor = describeStructuredWrapperBlock(block);
|
|
1092
|
+
const recursableBlockedReasonCode = descriptor
|
|
1093
|
+
? isBlockedImportFeatureKey(descriptor.featureKey)
|
|
1094
|
+
? "workflow_blocked_import"
|
|
1095
|
+
: "workflow_preserve_only"
|
|
1096
|
+
: getRecursableSdtBlockedReasonCode(block);
|
|
1089
1097
|
|
|
1090
1098
|
for (const child of block.children) {
|
|
1091
1099
|
const result = createSurfaceBlock(
|
|
@@ -1112,11 +1120,21 @@ function createSdtBlock(
|
|
|
1112
1120
|
...(block.properties.alias ? { alias: block.properties.alias } : {}),
|
|
1113
1121
|
...(block.properties.tag ? { tag: block.properties.tag } : {}),
|
|
1114
1122
|
...(block.properties.lock ? { lock: block.properties.lock } : {}),
|
|
1123
|
+
...(recursableBlockedReasonCode
|
|
1124
|
+
? { blockedReasonCode: recursableBlockedReasonCode }
|
|
1125
|
+
: {}),
|
|
1115
1126
|
...(block.properties.checkbox ? { checkboxChecked: block.properties.checkbox.checked } : {}),
|
|
1116
1127
|
...(block.properties.datePicker?.fullDate ? { dateValue: block.properties.datePicker.fullDate } : {}),
|
|
1117
1128
|
...(block.properties.dropdownList ? { dropdownItems: block.properties.dropdownList } : {}),
|
|
1118
1129
|
...(block.properties.comboBox ? { comboBoxItems: block.properties.comboBox } : {}),
|
|
1119
1130
|
...(block.properties.showingPlcHdr ? { showingPlcHdr: true } : {}),
|
|
1131
|
+
...(descriptor
|
|
1132
|
+
? {
|
|
1133
|
+
label: descriptor.label,
|
|
1134
|
+
detail: descriptor.detail,
|
|
1135
|
+
featureKey: descriptor.featureKey,
|
|
1136
|
+
}
|
|
1137
|
+
: {}),
|
|
1120
1138
|
children,
|
|
1121
1139
|
},
|
|
1122
1140
|
lockedFragmentIds,
|
|
@@ -1124,6 +1142,24 @@ function createSdtBlock(
|
|
|
1124
1142
|
};
|
|
1125
1143
|
}
|
|
1126
1144
|
|
|
1145
|
+
function getRecursableSdtBlockedReasonCode(
|
|
1146
|
+
block: Mutable<SdtNode>,
|
|
1147
|
+
): "workflow_preserve_only" | null {
|
|
1148
|
+
const searchText = [
|
|
1149
|
+
block.properties.alias,
|
|
1150
|
+
block.properties.tag,
|
|
1151
|
+
block.properties.sdtType,
|
|
1152
|
+
block.properties.propertiesXml,
|
|
1153
|
+
]
|
|
1154
|
+
.filter(Boolean)
|
|
1155
|
+
.join(" ")
|
|
1156
|
+
.toLowerCase();
|
|
1157
|
+
|
|
1158
|
+
return searchText.includes("table of contents") || /\btoc\b/u.test(searchText)
|
|
1159
|
+
? "workflow_preserve_only"
|
|
1160
|
+
: null;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1127
1163
|
function createParagraphBlock(
|
|
1128
1164
|
paragraphIndex: number,
|
|
1129
1165
|
paragraph: Mutable<ParagraphNode>,
|
|
@@ -1562,6 +1598,7 @@ function appendInlineSegments(
|
|
|
1562
1598
|
});
|
|
1563
1599
|
return { nextCursor: start + 1, lockedFragmentIds: [] };
|
|
1564
1600
|
}
|
|
1601
|
+
const objectAnchor = surfaceAnchorFromGeometry(node.anchor);
|
|
1565
1602
|
if (c.type === "chart_preview") {
|
|
1566
1603
|
const parsedChartId = registerParsedChartPreview(c, document);
|
|
1567
1604
|
return appendComplexPreviewSegment(
|
|
@@ -1573,7 +1610,7 @@ function appendInlineSegments(
|
|
|
1573
1610
|
{
|
|
1574
1611
|
previewMediaId: c.previewMediaId,
|
|
1575
1612
|
parsedChartId,
|
|
1576
|
-
anchor:
|
|
1613
|
+
...(objectAnchor ? { anchor: objectAnchor } : {}),
|
|
1577
1614
|
},
|
|
1578
1615
|
);
|
|
1579
1616
|
}
|
|
@@ -1586,7 +1623,7 @@ function appendInlineSegments(
|
|
|
1586
1623
|
`DrawingFrame smartart_preview (${node.anchor.wrapMode}).`,
|
|
1587
1624
|
{
|
|
1588
1625
|
previewMediaId: c.previewMediaId,
|
|
1589
|
-
anchor:
|
|
1626
|
+
...(objectAnchor ? { anchor: objectAnchor } : {}),
|
|
1590
1627
|
},
|
|
1591
1628
|
);
|
|
1592
1629
|
}
|
|
@@ -1596,7 +1633,9 @@ function appendInlineSegments(
|
|
|
1596
1633
|
start,
|
|
1597
1634
|
"Drawing frame",
|
|
1598
1635
|
`DrawingFrame ${c.type} (${node.anchor.wrapMode}).`,
|
|
1599
|
-
{
|
|
1636
|
+
{
|
|
1637
|
+
...(objectAnchor ? { anchor: objectAnchor } : {}),
|
|
1638
|
+
},
|
|
1600
1639
|
);
|
|
1601
1640
|
}
|
|
1602
1641
|
case "symbol":
|