@beyondwork/docx-react-component 1.0.66 → 1.0.69
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/README.md +75 -931
- package/package.json +26 -27
- package/src/api/anchor-conversion.ts +43 -0
- package/src/api/editor-state-types.ts +2 -1
- package/src/api/public-types.ts +504 -101
- package/src/api/session-state.ts +4 -0
- package/src/api/v3/README.md +91 -0
- package/src/api/v3/_create.ts +146 -0
- package/src/api/v3/_layer-metadata.ts +362 -0
- package/src/api/v3/_mocks.ts +84 -0
- package/src/api/v3/_runtime-handle.ts +162 -0
- package/src/api/v3/_ux-response.ts +73 -0
- package/src/api/v3/ai/_metadata-audit.ts +225 -0
- package/src/api/v3/ai/attach.ts +235 -0
- package/src/api/v3/ai/bundle.ts +132 -0
- package/src/api/v3/ai/explain.ts +144 -0
- package/src/api/v3/ai/export.ts +54 -0
- package/src/api/v3/ai/inspect.ts +118 -0
- package/src/api/v3/ai/policy.ts +77 -0
- package/src/api/v3/ai/replacement.ts +341 -0
- package/src/api/v3/ai/resolve.ts +133 -0
- package/src/api/v3/index.ts +79 -0
- package/src/api/v3/runtime/chart.ts +310 -0
- package/src/api/v3/runtime/clipboard.ts +81 -0
- package/src/api/v3/runtime/collab.ts +331 -0
- package/src/api/v3/runtime/content.ts +236 -0
- package/src/api/v3/runtime/document.ts +282 -0
- package/src/api/v3/runtime/formatting.ts +186 -0
- package/src/api/v3/runtime/geometry.ts +349 -0
- package/src/api/v3/runtime/layout.ts +108 -0
- package/src/api/v3/runtime/review.ts +129 -0
- package/src/api/v3/runtime/search.ts +74 -0
- package/src/api/v3/runtime/table.ts +63 -0
- package/src/api/v3/runtime/workflow.ts +434 -0
- package/src/api/v3/ui/_context.ts +86 -0
- package/src/api/v3/ui/_create.ts +65 -0
- package/src/api/v3/ui/_types.ts +520 -0
- package/src/api/v3/ui/chrome-composition.ts +342 -0
- package/src/{ui-tailwind/chrome → api/v3/ui}/chrome-preset-model.ts +11 -1
- package/src/api/v3/ui/chrome.ts +476 -0
- package/src/api/v3/ui/debug.ts +124 -0
- package/src/api/v3/ui/index.ts +64 -0
- package/src/api/v3/ui/overlays-visibility.ts +170 -0
- package/src/api/v3/ui/overlays.ts +427 -0
- package/src/api/v3/ui/scope.ts +71 -0
- package/src/api/v3/ui/session.ts +100 -0
- package/src/api/v3/ui/surface.ts +170 -0
- package/src/api/v3/ui/viewport.ts +303 -0
- package/src/core/commands/index.ts +28 -6
- package/src/core/commands/list-commands.ts +3 -2
- package/src/core/commands/section-layout-commands.ts +9 -8
- package/src/core/schema/text-schema.ts +16 -0
- package/src/core/selection/mapping.ts +33 -72
- package/src/core/state/editor-state.ts +96 -189
- package/src/index.ts +23 -4
- package/src/io/chart-preview-resolver.ts +1 -1
- package/src/io/docx-session.ts +36 -4795
- package/src/io/export/build-app-properties-xml.ts +1 -1
- package/src/io/export/serialize-comments.ts +1 -1
- package/src/io/export/serialize-headers-footers.ts +6 -1
- package/src/io/export/serialize-main-document.ts +45 -0
- package/src/io/export/serialize-run-formatting.ts +17 -2
- package/src/io/export/twip.ts +1 -1
- package/src/io/normalize/normalize-text.ts +27 -20
- package/src/io/ooxml/chart/parse-series.ts +1 -1
- package/src/io/ooxml/chart/resolve-color.ts +2 -2
- package/src/io/ooxml/chart/types.ts +1 -1
- package/src/io/ooxml/classify-embedding.ts +83 -33
- package/src/io/ooxml/parse-fill.ts +1 -1
- package/src/io/ooxml/parse-main-document.ts +71 -1
- package/src/io/ooxml/parse-object.ts +14 -10
- package/src/io/ooxml/parse-run-formatting.ts +47 -1
- package/src/io/ooxml/property-grab-bag.ts +2 -2
- package/src/io/ooxml/units.ts +11 -0
- package/src/io/ooxml/workflow-payload.ts +282 -7
- package/src/model/anchor.ts +85 -0
- package/src/model/canonical-document.ts +351 -15
- package/src/model/chart-types.ts +1 -1
- package/src/model/layout/index.ts +83 -0
- package/src/model/layout/page-graph-types.ts +181 -0
- package/src/model/layout/page-layout-snapshot.ts +105 -0
- package/src/model/layout/resolved-layout-types.ts +47 -0
- package/src/model/layout/runtime-page-graph-types.ts +102 -0
- package/src/model/paragraph-scope-ids.ts +72 -0
- package/src/model/review/comment-types.ts +112 -0
- package/src/model/review/index.ts +2 -0
- package/src/model/review/revision-types.ts +215 -0
- package/src/model/snapshot.ts +32 -0
- package/src/review/store/comment-store.ts +21 -47
- package/src/review/store/revision-types.ts +40 -198
- package/src/runtime/collab/base-doc-fingerprint.ts +6 -1
- package/src/runtime/collab/runtime-collab-sync.ts +13 -3
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/debug/build-debug-inspector-snapshot.ts +686 -0
- package/src/runtime/debug/event-ring-buffer.ts +64 -0
- package/src/runtime/debug/probability-sampler.ts +18 -0
- package/src/runtime/debug/runtime-debug-facet.ts +67 -0
- package/src/runtime/debug/stage-tokens.ts +31 -0
- package/src/runtime/debug/telemetry-bus.ts +271 -0
- package/src/runtime/debug/types.ts +275 -0
- package/src/runtime/debug/wrap-ref-for-telemetry.ts +118 -0
- package/src/runtime/document-layout.ts +8 -6
- package/src/runtime/document-runtime.ts +843 -1141
- package/src/runtime/document-search.ts +1 -1
- package/src/runtime/edit-ops/index.ts +1 -1
- package/src/runtime/external-send-runtime.ts +1 -1
- package/src/runtime/formatting/document-lookup.ts +235 -0
- package/src/runtime/formatting/field/registry.ts +41 -0
- package/src/runtime/{field-resolver.ts → formatting/field/resolver.ts} +27 -2
- package/src/runtime/formatting/font-resolution.ts +83 -0
- package/src/runtime/formatting/formatting-context.ts +903 -0
- package/src/runtime/formatting/formatting-types.ts +157 -0
- package/src/runtime/{hyperlink-color-resolver.ts → formatting/hyperlink-color.ts} +2 -2
- package/src/runtime/formatting/index.ts +125 -0
- package/src/runtime/{resolved-numbering-geometry.ts → formatting/numbering/geometry.ts} +1 -1
- package/src/runtime/{numbering-prefix.ts → formatting/numbering/prefix.ts} +170 -3
- package/src/runtime/formatting/paragraph-style-resolver.ts +92 -0
- package/src/runtime/formatting/projector.ts +75 -0
- package/src/runtime/formatting/resolve-effective.ts +407 -0
- package/src/runtime/formatting/revision-display.ts +105 -0
- package/src/runtime/{paragraph-style-resolver.ts → formatting/style-cascade.ts} +84 -141
- package/src/runtime/{table-style-resolver.ts → formatting/table-style-resolver.ts} +1 -1
- package/src/runtime/formatting/telemetry-bridge.ts +106 -0
- package/src/runtime/{theme-color-resolver.ts → formatting/theme-color.ts} +2 -30
- package/src/runtime/geometry/caret-geometry.ts +164 -0
- package/src/runtime/geometry/geometry-facet.ts +364 -0
- package/src/runtime/geometry/geometry-types.ts +256 -0
- package/src/runtime/geometry/hit-test.ts +125 -0
- package/src/runtime/geometry/index.ts +71 -0
- package/src/runtime/geometry/inert-geometry-facet.ts +43 -0
- package/src/runtime/geometry/invalidation.ts +35 -0
- package/src/runtime/geometry/object-handles.ts +77 -0
- package/src/runtime/geometry/overlay-rects.ts +85 -0
- package/src/runtime/geometry/project-anchors.ts +100 -0
- package/src/runtime/geometry/project-fragments.ts +216 -0
- package/src/runtime/geometry/projector.ts +129 -0
- package/src/runtime/geometry/replacement-envelope.ts +130 -0
- package/src/runtime/geometry/viewport.ts +218 -0
- package/src/runtime/layout/compat-input-ledger.ts +211 -0
- package/src/runtime/layout/index.ts +6 -1
- package/src/runtime/layout/inert-layout-facet.ts +12 -7
- package/src/runtime/layout/layout-engine-instance.ts +189 -11
- package/src/runtime/layout/layout-engine-version.ts +450 -1
- package/src/runtime/layout/layout-facet-types.ts +60 -0
- package/src/runtime/layout/layout-measurement-provider.ts +13 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +14 -2
- package/src/runtime/layout/measurement-backend-empirical.ts +23 -4
- package/src/runtime/layout/page-graph.ts +62 -209
- package/src/runtime/layout/page-story-resolver.ts +7 -12
- package/src/runtime/layout/paginated-layout-engine.ts +186 -11
- package/src/runtime/layout/project-block-fragments.ts +11 -0
- package/src/runtime/layout/projector.ts +90 -0
- package/src/runtime/layout/public-facet.ts +187 -442
- package/src/runtime/layout/resolved-formatting-state.ts +158 -26
- package/src/runtime/layout/table-render-plan.ts +1 -1
- package/src/runtime/prerender/cache-envelope.ts +6 -1
- package/src/runtime/prerender/prerender-document.ts +18 -23
- package/src/runtime/render/decoration-resolver.ts +1 -1
- package/src/runtime/render/render-frame-types.ts +20 -0
- package/src/runtime/render/render-kernel.ts +94 -25
- package/src/runtime/scopes/_formatting-seam.ts +262 -0
- package/src/runtime/scopes/_scope-dependencies.ts +49 -0
- package/src/runtime/scopes/action-validation.ts +356 -0
- package/src/runtime/scopes/attach-explanation.ts +102 -0
- package/src/runtime/scopes/audit-bundle.ts +71 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +163 -0
- package/src/runtime/scopes/compile-scope.ts +262 -0
- package/src/runtime/scopes/compiler-service.ts +431 -0
- package/src/runtime/scopes/create-issue.ts +107 -0
- package/src/runtime/scopes/enumerate-scopes.ts +543 -0
- package/src/runtime/scopes/evidence.ts +233 -0
- package/src/runtime/scopes/index.ts +150 -0
- package/src/runtime/scopes/position-map.ts +214 -0
- package/src/runtime/scopes/preservation-boundary.ts +91 -0
- package/src/runtime/scopes/projector.ts +49 -0
- package/src/runtime/scopes/replaceability.ts +87 -0
- package/src/runtime/scopes/replacement/apply.ts +228 -0
- package/src/runtime/scopes/replacement/compile.ts +59 -0
- package/src/runtime/scopes/replacement/propose.ts +42 -0
- package/src/runtime/scopes/resolve-reference.ts +347 -0
- package/src/runtime/scopes/review-bundle.ts +141 -0
- package/src/runtime/scopes/scope-kinds/_paragraph-text.ts +57 -0
- package/src/runtime/scopes/scope-kinds/_table-text.ts +42 -0
- package/src/runtime/scopes/scope-kinds/comment-thread.ts +59 -0
- package/src/runtime/scopes/scope-kinds/field.ts +65 -0
- package/src/runtime/scopes/scope-kinds/heading.ts +84 -0
- package/src/runtime/scopes/scope-kinds/list-item.ts +77 -0
- package/src/runtime/scopes/scope-kinds/paragraph.ts +182 -0
- package/src/runtime/scopes/scope-kinds/revision.ts +62 -0
- package/src/runtime/scopes/scope-kinds/table-cell.ts +57 -0
- package/src/runtime/scopes/scope-kinds/table-row.ts +61 -0
- package/src/runtime/scopes/scope-kinds/table.ts +55 -0
- package/src/runtime/scopes/scope-range.ts +208 -0
- package/src/runtime/scopes/semantic-scope-types.ts +454 -0
- package/src/runtime/scopes/workflow-overlap.ts +92 -0
- package/src/runtime/selection/index.ts +1 -1
- package/src/runtime/structure-ops/fragment-insert.ts +1 -1
- package/src/runtime/structure-ops/index.ts +1 -1
- package/src/runtime/surface-projection.ts +232 -262
- package/src/runtime/units.ts +4 -2
- package/src/runtime/workflow/coordinator.ts +1348 -0
- package/src/runtime/workflow/derived-scope-resolver.ts +125 -0
- package/src/runtime/workflow/index.ts +25 -0
- package/src/runtime/workflow/markup-mode-policy.ts +98 -0
- package/src/runtime/{workflow-markup.ts → workflow/markup.ts} +6 -6
- package/src/runtime/workflow/metadata-persistence.ts +306 -0
- package/src/runtime/workflow/metadata-writer.ts +123 -0
- package/src/runtime/workflow/overlay-store.ts +690 -0
- package/src/runtime/workflow/projector.ts +127 -0
- package/src/runtime/{query-scopes.ts → workflow/query-scopes.ts} +3 -3
- package/src/runtime/{workflow-rail-segments.ts → workflow/rail/compose.ts} +60 -165
- package/src/runtime/workflow/rail/types.ts +198 -0
- package/src/runtime/workflow/scope-rail-composer.ts +39 -0
- package/src/runtime/{scope-resolver.ts → workflow/scope-resolver.ts} +3 -3
- package/src/runtime/workflow/scope-writer.ts +188 -0
- package/src/runtime/{tamper-gate.ts → workflow/tamper-gate.ts} +1 -1
- package/src/runtime/workflow/visibility-policy.ts +129 -0
- package/src/session/_sync-legacy.ts +66 -0
- package/src/session/export/embedded-reconstitute.ts +104 -0
- package/src/session/export/export-diagnostics.ts +85 -0
- package/src/session/export/export-validation.ts +110 -0
- package/src/session/export/index.ts +34 -0
- package/src/session/export/preservation-reattach.ts +30 -0
- package/src/session/export/serialize-dispatch.ts +165 -0
- package/src/session/export/stateful-export-pipeline.ts +432 -0
- package/src/session/export/stateful-export.ts +684 -0
- package/src/session/import/canonical-assembly.ts +227 -0
- package/src/session/import/diagnostics-session.ts +54 -0
- package/src/session/import/embedded-discovery.ts +225 -0
- package/src/session/import/embedded-offload.ts +337 -0
- package/src/session/import/import-diagnostics.ts +69 -0
- package/src/session/import/loader-types.ts +313 -0
- package/src/session/import/loader.ts +1834 -0
- package/src/session/import/normalize.ts +195 -0
- package/src/session/import/package-parts.ts +217 -0
- package/src/session/import/package-read.ts +195 -0
- package/src/session/import/parse-orchestration.ts +105 -0
- package/src/session/import/part-constants.ts +70 -0
- package/src/session/import/part-discovery.ts +94 -0
- package/src/session/import/preservation-index.ts +46 -0
- package/src/{runtime/read-only-diagnostics-runtime.ts → session/import/read-only-diagnostics.ts} +24 -3
- package/src/session/import/review-import.ts +508 -0
- package/src/session/import/styles-consolidation.ts +281 -0
- package/src/session/import/workflow-scope-import.ts +256 -0
- package/src/session/index.ts +37 -0
- package/src/session/session-state.ts +69 -0
- package/src/session/session.ts +532 -0
- package/src/session/shared/protection.ts +228 -0
- package/src/session/shared/session-utils.ts +82 -0
- package/src/session/types.ts +499 -0
- package/src/shell/chart-snapshots.ts +96 -0
- package/src/shell/media-previews.ts +85 -0
- package/src/shell/overlay-anchor-bridge.ts +53 -0
- package/src/shell/paste-adapter.ts +23 -0
- package/src/shell/ref-commands.ts +1697 -0
- package/src/shell/ref-utilities.ts +48 -0
- package/src/shell/search.ts +51 -0
- package/src/{ui/editor-runtime-boundary.ts → shell/session-bootstrap.ts} +243 -67
- package/src/shell/ui-subscriber-channels.ts +81 -0
- package/src/shell/use-collab-sync.ts +116 -0
- package/src/ui/WordReviewEditor.tsx +496 -2051
- package/src/ui/editor-shell-view.tsx +30 -1
- package/src/ui/editor-surface-controller.tsx +49 -1
- package/src/ui/headless/revision-decoration-model.ts +83 -0
- package/src/{ui-tailwind/chrome → ui/headless}/role-action-sets.ts +1 -1
- package/src/ui/headless/scoped-chrome-policy.ts +2 -2
- package/src/ui/headless/selection-tool-context.ts +1 -1
- package/src/ui/headless/selection-tool-resolver.ts +1 -1
- package/src/ui/runtime-shortcut-dispatch.ts +46 -1
- package/src/ui/ui-controller-factory.ts +221 -0
- package/src/ui-tailwind/chart/ChartSurface.tsx +2 -2
- package/src/ui-tailwind/chart/layout/legend-layout.ts +1 -1
- package/src/ui-tailwind/chart/layout/plot-area.ts +2 -2
- package/src/ui-tailwind/chart/layout/title-layout.ts +1 -1
- package/src/ui-tailwind/chart/render/area.tsx +3 -3
- package/src/ui-tailwind/chart/render/bar-column.tsx +3 -3
- package/src/ui-tailwind/chart/render/bubble.tsx +3 -3
- package/src/ui-tailwind/chart/render/combo.tsx +2 -2
- package/src/ui-tailwind/chart/render/data-labels.tsx +2 -2
- package/src/ui-tailwind/chart/render/font-metrics.ts +2 -2
- package/src/ui-tailwind/chart/render/line.tsx +3 -3
- package/src/ui-tailwind/chart/render/pie.tsx +6 -6
- package/src/ui-tailwind/chart/render/scatter.tsx +3 -3
- package/src/ui-tailwind/chart/render/svg-primitives.ts +3 -3
- package/src/ui-tailwind/chart/render/unsupported.tsx +2 -2
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +88 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +1 -1
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +1 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +553 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +182 -0
- package/src/ui-tailwind/chrome/local-surface-arbiter.ts +534 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +226 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-context-band.tsx +125 -0
- package/src/ui-tailwind/chrome/tw-context-menu-portal.tsx +248 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +42 -1
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +8 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +38 -4
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +104 -6
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +66 -7
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +54 -8
- package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +33 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +78 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +16 -8
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +276 -0
- package/src/ui-tailwind/chrome/use-context-menu-controller.ts +201 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +22 -4
- package/src/ui-tailwind/chrome-overlay/tw-comment-balloon-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-locked-block-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +11 -5
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +197 -3
- package/src/ui-tailwind/chrome-overlay/tw-revision-margin-bar-layer.tsx +1 -1
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +35 -6
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +24 -16
- package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +1 -1
- package/src/ui-tailwind/debug/README.md +57 -0
- package/src/ui-tailwind/debug/index.ts +3 -0
- package/src/ui-tailwind/debug/tw-debug-overlay.tsx +186 -0
- package/src/ui-tailwind/debug/tw-debug-presentation.tsx +80 -0
- package/src/ui-tailwind/debug/tw-debug-top-bar.tsx +83 -0
- package/src/ui-tailwind/editor-surface/chart-node-view.tsx +2 -2
- package/src/ui-tailwind/editor-surface/float-wrap-resolver.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +135 -10
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +40 -13
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +3 -3
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +1 -1
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +2 -2
- package/src/ui-tailwind/editor-surface/scroll-anchor.ts +91 -9
- package/src/ui-tailwind/editor-surface/shape-renderer.ts +1 -1
- package/src/ui-tailwind/editor-surface/surface-layer.ts +1 -1
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +1 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +23 -6
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +132 -22
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +1 -1
- package/src/ui-tailwind/index.ts +0 -5
- package/src/ui-tailwind/overlay-anchor-bridge-context.tsx +33 -0
- package/src/ui-tailwind/page-stack/floating-image-overlay-model.ts +66 -29
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +25 -2
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +15 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +92 -4
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +1 -1
- package/src/ui-tailwind/review-workspace/page-chrome.ts +210 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +101 -0
- package/src/ui-tailwind/review-workspace/paragraph-layout.ts +115 -0
- package/src/ui-tailwind/review-workspace/selection-toolbar-placement.ts +97 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-navigator.tsx +130 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-page-toolbar.tsx +240 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +59 -0
- package/src/ui-tailwind/review-workspace/types.ts +408 -0
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +104 -0
- package/src/ui-tailwind/review-workspace/use-derived-view-state.ts +151 -0
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +70 -0
- package/src/ui-tailwind/review-workspace/use-grabbed-segment-offsets.ts +40 -0
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +130 -0
- package/src/ui-tailwind/review-workspace/use-pm-surface-capture.ts +60 -0
- package/src/ui-tailwind/review-workspace/use-review-rail-state.ts +63 -0
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +170 -0
- package/src/ui-tailwind/review-workspace/use-scroll-root-capture.ts +28 -0
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +113 -0
- package/src/ui-tailwind/review-workspace/use-shell-selection-anchor-bridge.ts +120 -0
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +55 -0
- package/src/ui-tailwind/review-workspace/use-viewport-dimensions.ts +43 -0
- package/src/ui-tailwind/review-workspace/use-workspace-arbiter.ts +25 -0
- package/src/ui-tailwind/review-workspace/use-workspace-composition.ts +86 -0
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +150 -0
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +61 -98
- package/src/ui-tailwind/tw-review-workspace.tsx +521 -1802
- package/src/ui-tailwind/ui-api-context.tsx +43 -0
- package/src/ui-tailwind/ui-shell-channels-context.tsx +49 -0
- package/src/validation/compatibility-engine.ts +6 -6
- package/src/runtime/styles-cascade.ts +0 -33
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +0 -85
- /package/src/runtime/{page-number-format.ts → formatting/field/page-number-format.ts} +0 -0
- /package/src/runtime/{ai-action-policy.ts → workflow/ai-action-policy.ts} +0 -0
- /package/src/runtime/{scope-tag-registry.ts → workflow/scope-tag-registry.ts} +0 -0
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
// @internal — Debug projector.
|
|
2
|
+
//
|
|
3
|
+
// Composes already-shipped DocumentRuntime reads into one typed
|
|
4
|
+
// `DebugInspectorSnapshot`. Consumed in two places:
|
|
5
|
+
//
|
|
6
|
+
// 1. The harness dev drawer — `HarnessDebugPanel` retargets off its
|
|
7
|
+
// current per-snapshot props onto a single `DebugInspectorSnapshot`
|
|
8
|
+
// read here.
|
|
9
|
+
// 2. The Phase 2 `services/debug/` Railway service — the hidden
|
|
10
|
+
// `/session/[id]` page exposes `window.__debug.captureDebugSnapshot(query)`
|
|
11
|
+
// that calls this function on the mounted editor's runtime; agents
|
|
12
|
+
// fetch the same JSON through the HTTPS API.
|
|
13
|
+
//
|
|
14
|
+
// Priority ordering (user intent 2026-04-20):
|
|
15
|
+
// 1. Scope debugging — drives `ScopeDebugEntry[]` with the three-way
|
|
16
|
+
// source discrimination (`marker-backed` | `overlay-only` | `detached`).
|
|
17
|
+
// 2. OOXML audit — surfaced via `health.warnings` + `health.compatibility`
|
|
18
|
+
// and through the Phase 2 service's scenarios.
|
|
19
|
+
// 3. Rendering — secondary; `layout` is minimal in Phase 0.
|
|
20
|
+
//
|
|
21
|
+
// Perf note: read-only. No DOM measurement. No PM state inspection. Every
|
|
22
|
+
// read is an already-shipped runtime method. See CLAUDE.md perf invariants
|
|
23
|
+
// 1, 4, 7.
|
|
24
|
+
//
|
|
25
|
+
// F-7 / api-channel scope: every runtime read below goes through `safeCall`
|
|
26
|
+
// (see bottom of file) which invokes the method directly on the runtime
|
|
27
|
+
// object. `api`-channel emissions come from the `wrapRefForTelemetry` Proxy
|
|
28
|
+
// applied at `src/ui/WordReviewEditor.tsx` around the `useImperativeHandle`
|
|
29
|
+
// ref — NOT from the runtime itself. So building a DebugInspectorSnapshot
|
|
30
|
+
// never emits `api` events. This is architectural, not a bug: the debug
|
|
31
|
+
// service's own internal reads must not pollute the trace that records
|
|
32
|
+
// agent-origin method calls. See
|
|
33
|
+
// `services/debug/docs/substrate-code-review-2026-04-20.md` §F-7.
|
|
34
|
+
|
|
35
|
+
import type { CanonicalDocumentEnvelope } from "../../core/state/editor-state.ts";
|
|
36
|
+
import type { DocumentRuntime } from "../document-runtime.ts";
|
|
37
|
+
import { collectScopeLocations } from "../workflow/scope-resolver.ts";
|
|
38
|
+
import { projectWorkflowDebugEntry } from "../workflow/projector.ts";
|
|
39
|
+
import type {
|
|
40
|
+
EditorWarning,
|
|
41
|
+
ScopeQueryResult,
|
|
42
|
+
WorkflowOverlay,
|
|
43
|
+
WorkflowScope,
|
|
44
|
+
} from "../../api/public-types.ts";
|
|
45
|
+
import type {
|
|
46
|
+
DebugInspectorHealthSection,
|
|
47
|
+
DebugInspectorLayoutSection,
|
|
48
|
+
DebugInspectorQuery,
|
|
49
|
+
DebugInspectorReviewSection,
|
|
50
|
+
DebugInspectorSelectionSection,
|
|
51
|
+
DebugInspectorSessionSection,
|
|
52
|
+
DebugInspectorSnapshot,
|
|
53
|
+
DebugInspectorWorkflowSection,
|
|
54
|
+
RuntimeTelemetryEvent,
|
|
55
|
+
ScopeDebugEntry,
|
|
56
|
+
ScopeDebugSource,
|
|
57
|
+
ScopeMarkerState,
|
|
58
|
+
} from "./types.ts";
|
|
59
|
+
import type { TelemetryBus } from "./telemetry-bus.ts";
|
|
60
|
+
import { buildFormattingDebugEntry } from "../formatting/projector.ts";
|
|
61
|
+
import { buildLayoutDebugEntry } from "../layout/projector.ts";
|
|
62
|
+
import { createGeometryFacet } from "../geometry/geometry-facet.ts";
|
|
63
|
+
import { buildGeometryDebugEntry } from "../geometry/projector.ts";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Optional `TelemetryBus` accessor — when passed, the projector pulls the
|
|
67
|
+
* recent event tail and the current channel state into the snapshot. When
|
|
68
|
+
* absent the snapshot omits `events` / `channels` (Phase 0 callers).
|
|
69
|
+
*/
|
|
70
|
+
export interface BuildDebugInspectorSnapshotOptions {
|
|
71
|
+
readonly bus?: TelemetryBus;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function buildDebugInspectorSnapshot(
|
|
75
|
+
runtime: DocumentRuntime,
|
|
76
|
+
query?: DebugInspectorQuery,
|
|
77
|
+
options?: BuildDebugInspectorSnapshotOptions,
|
|
78
|
+
): DebugInspectorSnapshot {
|
|
79
|
+
const partialFallbacks: string[] = [];
|
|
80
|
+
|
|
81
|
+
const session = projectSession(runtime, partialFallbacks);
|
|
82
|
+
|
|
83
|
+
const warnings = safeCall(runtime, (r) => r.getWarnings(), [], partialFallbacks, "warnings");
|
|
84
|
+
const compatibility = safeCall(
|
|
85
|
+
runtime,
|
|
86
|
+
(r) => r.getCompatibilityReport(),
|
|
87
|
+
null,
|
|
88
|
+
partialFallbacks,
|
|
89
|
+
"compatibility",
|
|
90
|
+
);
|
|
91
|
+
const guard = safeCall(
|
|
92
|
+
runtime,
|
|
93
|
+
(r) => r.getInteractionGuardSnapshot(),
|
|
94
|
+
null,
|
|
95
|
+
partialFallbacks,
|
|
96
|
+
"interaction-guard",
|
|
97
|
+
);
|
|
98
|
+
const fatalError = extractFatalError(runtime, partialFallbacks);
|
|
99
|
+
const protection = safeCall(
|
|
100
|
+
runtime,
|
|
101
|
+
(r) => r.getProtectionSnapshot(),
|
|
102
|
+
null,
|
|
103
|
+
partialFallbacks,
|
|
104
|
+
"protection",
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const health: DebugInspectorHealthSection = {
|
|
108
|
+
compatibility: compatibility ?? emptyCompatibilityReport(),
|
|
109
|
+
warnings,
|
|
110
|
+
blockedReasons: guard?.blockedReasons ?? [],
|
|
111
|
+
fatalError,
|
|
112
|
+
readOnly:
|
|
113
|
+
protection?.enforcementActive === true && protection?.editType === "readOnly",
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const context = safeCall(
|
|
117
|
+
runtime,
|
|
118
|
+
(r) => r.getRuntimeContextAnalytics(),
|
|
119
|
+
null,
|
|
120
|
+
partialFallbacks,
|
|
121
|
+
"context-analytics",
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const selection = projectSelection(runtime, partialFallbacks);
|
|
125
|
+
|
|
126
|
+
const overlay = safeCall(
|
|
127
|
+
runtime,
|
|
128
|
+
(r) => r.getWorkflowOverlay(),
|
|
129
|
+
null,
|
|
130
|
+
partialFallbacks,
|
|
131
|
+
"workflow-overlay",
|
|
132
|
+
);
|
|
133
|
+
const scopeResults = safeCall(
|
|
134
|
+
runtime,
|
|
135
|
+
(r) => r.queryScopes(),
|
|
136
|
+
[] as ScopeQueryResult[],
|
|
137
|
+
partialFallbacks,
|
|
138
|
+
"query-scopes",
|
|
139
|
+
);
|
|
140
|
+
const markerBacked = safeCall(
|
|
141
|
+
runtime,
|
|
142
|
+
(r) => r.getMarkerBackedScopeIds(),
|
|
143
|
+
new Set<string>(),
|
|
144
|
+
partialFallbacks,
|
|
145
|
+
"marker-backed-ids",
|
|
146
|
+
);
|
|
147
|
+
const document = safeGetDocument(runtime, partialFallbacks);
|
|
148
|
+
const markerLocations = document
|
|
149
|
+
? collectScopeLocations(document)
|
|
150
|
+
: new Map<string, { startPos?: number; endPos?: number }>();
|
|
151
|
+
|
|
152
|
+
const scopes = projectScopes({
|
|
153
|
+
runtime,
|
|
154
|
+
scopeResults,
|
|
155
|
+
overlay,
|
|
156
|
+
markerBackedScopeIds: markerBacked,
|
|
157
|
+
markerLocations,
|
|
158
|
+
warnings,
|
|
159
|
+
scopeFilter: query?.scopeFilter,
|
|
160
|
+
partialFallbacks,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const scopeChannelOn = options?.bus?.getChannels?.().scope ?? false;
|
|
164
|
+
const warningChannelOn = options?.bus?.getChannels?.().warning ?? false;
|
|
165
|
+
const includeDebugEntry = scopeChannelOn || warningChannelOn;
|
|
166
|
+
const workflow = projectWorkflow(
|
|
167
|
+
overlay,
|
|
168
|
+
scopes,
|
|
169
|
+
includeDebugEntry ? runtime : null,
|
|
170
|
+
partialFallbacks,
|
|
171
|
+
);
|
|
172
|
+
const review = projectReview(runtime, partialFallbacks);
|
|
173
|
+
const layout = projectLayout(runtime, partialFallbacks);
|
|
174
|
+
|
|
175
|
+
const events: readonly RuntimeTelemetryEvent[] | undefined =
|
|
176
|
+
query?.includeEvents && options?.bus
|
|
177
|
+
? options.bus.tailAll(query.maxEvents ?? 64)
|
|
178
|
+
: query?.includeEvents
|
|
179
|
+
? []
|
|
180
|
+
: undefined;
|
|
181
|
+
|
|
182
|
+
// Phase C1 — formatting projector gate.
|
|
183
|
+
// Channel-gated + document-dependent. Zero cost when off.
|
|
184
|
+
const formatting =
|
|
185
|
+
options?.bus?.isEnabled("formatting") && document
|
|
186
|
+
? buildFormattingDebugEntry({ doc: document })
|
|
187
|
+
: undefined;
|
|
188
|
+
|
|
189
|
+
// Refactor/04 Slice 3 — layout projector gate. Channel-gated; reads
|
|
190
|
+
// existing facet state only (no pagination triggered). Zero cost when
|
|
191
|
+
// off.
|
|
192
|
+
const layoutDebug = options?.bus?.isEnabled("layout")
|
|
193
|
+
? buildLayoutDebugEntry({
|
|
194
|
+
facet: runtime.getLayoutFacet(),
|
|
195
|
+
// Task 5 — surface the compat-input ledger when the document
|
|
196
|
+
// envelope is available. When the debug path runs against a
|
|
197
|
+
// runtime with no canonical fallback, `document` is undefined
|
|
198
|
+
// and the projector omits `compatInputs`.
|
|
199
|
+
...(document?.subParts?.settings
|
|
200
|
+
? { settings: document.subParts.settings }
|
|
201
|
+
: {}),
|
|
202
|
+
})
|
|
203
|
+
: undefined;
|
|
204
|
+
|
|
205
|
+
// Refactor/05 Slice 6 closure gap — `DebugInspectorSnapshot.geometry?`
|
|
206
|
+
// was declared in v35 but `build-debug-inspector-snapshot.ts` never
|
|
207
|
+
// called `buildGeometryDebugEntry`, so the declared field was always
|
|
208
|
+
// `undefined` even with the `layout` channel on. Wiring it here closes
|
|
209
|
+
// that closure gap. The mounted shell owns the long-lived geometry
|
|
210
|
+
// facet via its render kernel; this debug-path instance is a
|
|
211
|
+
// lightweight facet constructed on demand from the runtime's layout
|
|
212
|
+
// facet (no kernel → Slice-1-proxy path), which is sufficient for the
|
|
213
|
+
// projector to read frame-independent fields (`pageCount`, viewport
|
|
214
|
+
// scaffolding, and the sample-block id projection). Channel-gated so
|
|
215
|
+
// cold path cost stays zero. When `refactor/05` follow-up exposes
|
|
216
|
+
// `runtime.getGeometryFacet()`, swap to that handle and drop the
|
|
217
|
+
// on-demand factory call.
|
|
218
|
+
const geometry = options?.bus?.isEnabled("layout")
|
|
219
|
+
? buildGeometryDebugEntry({
|
|
220
|
+
facet: createGeometryFacet({ layoutFacet: runtime.getLayoutFacet() }),
|
|
221
|
+
pageCount: runtime.getLayoutFacet().getPageCount(),
|
|
222
|
+
})
|
|
223
|
+
: undefined;
|
|
224
|
+
|
|
225
|
+
const snapshot: DebugInspectorSnapshot = {
|
|
226
|
+
schemaVersion: 1,
|
|
227
|
+
generatedAtUtc: new Date().toISOString(),
|
|
228
|
+
session,
|
|
229
|
+
health,
|
|
230
|
+
context,
|
|
231
|
+
selection,
|
|
232
|
+
workflow,
|
|
233
|
+
scopes,
|
|
234
|
+
review,
|
|
235
|
+
layout,
|
|
236
|
+
...(events !== undefined ? { events } : {}),
|
|
237
|
+
...(query?.includeTextProjection ? { textProjection: null } : {}),
|
|
238
|
+
...(partialFallbacks.length > 0 ? { partialFallbacks } : {}),
|
|
239
|
+
...(options?.bus ? { channels: options.bus.getChannels() } : {}),
|
|
240
|
+
...(formatting !== undefined ? { formatting } : {}),
|
|
241
|
+
...(layoutDebug !== undefined ? { layoutDebug } : {}),
|
|
242
|
+
...(geometry !== undefined ? { geometry } : {}),
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
return snapshot;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* -------------------------------------------------------------------------- */
|
|
249
|
+
|
|
250
|
+
function projectSession(
|
|
251
|
+
runtime: DocumentRuntime,
|
|
252
|
+
fallbacks: string[],
|
|
253
|
+
): DebugInspectorSessionSection {
|
|
254
|
+
const render = safeCall(
|
|
255
|
+
runtime,
|
|
256
|
+
(r) => r.getRenderSnapshot(),
|
|
257
|
+
null,
|
|
258
|
+
fallbacks,
|
|
259
|
+
"render-snapshot-session",
|
|
260
|
+
) as {
|
|
261
|
+
documentId?: string;
|
|
262
|
+
sessionId?: string;
|
|
263
|
+
isDirty?: boolean;
|
|
264
|
+
documentMode?: string;
|
|
265
|
+
activeStory?: DebugInspectorSessionSection["activeStory"];
|
|
266
|
+
} | null;
|
|
267
|
+
const viewState = safeCall(
|
|
268
|
+
runtime,
|
|
269
|
+
(r) => r.getViewState(),
|
|
270
|
+
null,
|
|
271
|
+
fallbacks,
|
|
272
|
+
"view-state",
|
|
273
|
+
) as {
|
|
274
|
+
workspaceMode?: "canvas" | "page";
|
|
275
|
+
viewMode?: string;
|
|
276
|
+
measurementFidelity?: string | null;
|
|
277
|
+
} | null;
|
|
278
|
+
const pageLayout = safeCall(
|
|
279
|
+
runtime,
|
|
280
|
+
(r) => r.getPageLayoutSnapshot(),
|
|
281
|
+
null,
|
|
282
|
+
fallbacks,
|
|
283
|
+
"page-layout",
|
|
284
|
+
) as { currentPage?: number } | null;
|
|
285
|
+
const exportBlocked =
|
|
286
|
+
(safeCall(
|
|
287
|
+
runtime,
|
|
288
|
+
(r) => r.getCompatibilityReport(),
|
|
289
|
+
null,
|
|
290
|
+
fallbacks,
|
|
291
|
+
"compat-for-session",
|
|
292
|
+
) as { blockExport?: boolean } | null)?.blockExport === true;
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
documentId: render?.documentId ?? "",
|
|
296
|
+
sessionId: render?.sessionId ?? "",
|
|
297
|
+
dirty: render?.isDirty ?? false,
|
|
298
|
+
exportBlocked: exportBlocked ?? false,
|
|
299
|
+
activeStory: render?.activeStory ?? { kind: "main" },
|
|
300
|
+
workspaceMode: viewState?.workspaceMode ?? "canvas",
|
|
301
|
+
viewMode: viewState?.viewMode ?? "editing",
|
|
302
|
+
documentMode: render?.documentMode ?? "editing",
|
|
303
|
+
measurementFidelity: viewState?.measurementFidelity ?? null,
|
|
304
|
+
currentPage: pageLayout?.currentPage ?? null,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function projectSelection(
|
|
309
|
+
runtime: DocumentRuntime,
|
|
310
|
+
fallbacks: string[],
|
|
311
|
+
): DebugInspectorSelectionSection {
|
|
312
|
+
const render = safeCall(runtime, (r) => r.getRenderSnapshot(), null, fallbacks, "render-snapshot");
|
|
313
|
+
const anchor =
|
|
314
|
+
(render as { selection?: { activeRange?: unknown } } | null)?.selection?.activeRange ??
|
|
315
|
+
null;
|
|
316
|
+
const location = anchor
|
|
317
|
+
? safeCall(
|
|
318
|
+
runtime,
|
|
319
|
+
(r) => r.getLocationForAnchor(anchor as never),
|
|
320
|
+
null,
|
|
321
|
+
fallbacks,
|
|
322
|
+
"location-for-anchor",
|
|
323
|
+
)
|
|
324
|
+
: safeCall(
|
|
325
|
+
runtime,
|
|
326
|
+
(r) => r.getCurrentLocation(),
|
|
327
|
+
null,
|
|
328
|
+
fallbacks,
|
|
329
|
+
"current-location",
|
|
330
|
+
);
|
|
331
|
+
return { anchor: anchor as never, location };
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
interface ProjectScopesInput {
|
|
335
|
+
runtime: DocumentRuntime;
|
|
336
|
+
scopeResults: ScopeQueryResult[];
|
|
337
|
+
overlay: WorkflowOverlay | null;
|
|
338
|
+
markerBackedScopeIds: ReadonlySet<string>;
|
|
339
|
+
markerLocations: Map<string, { startPos?: number; endPos?: number }>;
|
|
340
|
+
warnings: readonly EditorWarning[];
|
|
341
|
+
scopeFilter: DebugInspectorQuery["scopeFilter"];
|
|
342
|
+
partialFallbacks: string[];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function projectScopes(input: ProjectScopesInput): ScopeDebugEntry[] {
|
|
346
|
+
const {
|
|
347
|
+
runtime,
|
|
348
|
+
scopeResults,
|
|
349
|
+
overlay,
|
|
350
|
+
markerBackedScopeIds,
|
|
351
|
+
markerLocations,
|
|
352
|
+
warnings,
|
|
353
|
+
scopeFilter,
|
|
354
|
+
partialFallbacks,
|
|
355
|
+
} = input;
|
|
356
|
+
|
|
357
|
+
const overlayById = new Map<string, WorkflowScope>();
|
|
358
|
+
for (const scope of overlay?.scopes ?? []) {
|
|
359
|
+
overlayById.set(scope.scopeId, scope);
|
|
360
|
+
}
|
|
361
|
+
const warningByScope = new Map<string, EditorWarning>();
|
|
362
|
+
for (const warning of warnings) {
|
|
363
|
+
const scopeId = (warning as { scopeId?: string }).scopeId;
|
|
364
|
+
if (scopeId && !warningByScope.has(scopeId)) {
|
|
365
|
+
warningByScope.set(scopeId, warning);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const entries: ScopeDebugEntry[] = [];
|
|
370
|
+
const seen = new Set<string>();
|
|
371
|
+
|
|
372
|
+
const allIds = new Set<string>([
|
|
373
|
+
...scopeResults.map((r) => r.scope.scopeId),
|
|
374
|
+
...(overlay?.scopes.map((s) => s.scopeId) ?? []),
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
for (const scopeId of allIds) {
|
|
378
|
+
if (seen.has(scopeId)) continue;
|
|
379
|
+
seen.add(scopeId);
|
|
380
|
+
|
|
381
|
+
const queryResult = scopeResults.find((r) => r.scope.scopeId === scopeId) ?? null;
|
|
382
|
+
const overlayScope = overlayById.get(scopeId) ?? null;
|
|
383
|
+
const marker = markerLocations.get(scopeId);
|
|
384
|
+
const markerState: ScopeMarkerState = deriveMarkerState(marker);
|
|
385
|
+
const liveScope = safeCall(
|
|
386
|
+
runtime,
|
|
387
|
+
(r) => r.getScope(scopeId),
|
|
388
|
+
null,
|
|
389
|
+
partialFallbacks,
|
|
390
|
+
`get-scope:${scopeId}`,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const liveAnchor =
|
|
394
|
+
liveScope?.anchor ??
|
|
395
|
+
overlayScope?.anchor ??
|
|
396
|
+
({ kind: "detached", lastKnownRange: { from: 0, to: 0 }, reason: "deleted" } as const);
|
|
397
|
+
const isLiveDetached =
|
|
398
|
+
liveAnchor !== null &&
|
|
399
|
+
typeof liveAnchor === "object" &&
|
|
400
|
+
(liveAnchor as { kind?: string }).kind === "detached";
|
|
401
|
+
|
|
402
|
+
let source: ScopeDebugSource;
|
|
403
|
+
if (isLiveDetached) {
|
|
404
|
+
source = "detached";
|
|
405
|
+
} else if (markerBackedScopeIds.has(scopeId) && markerState === "complete") {
|
|
406
|
+
source = "marker-backed";
|
|
407
|
+
} else if (markerBackedScopeIds.has(scopeId)) {
|
|
408
|
+
source = "detached";
|
|
409
|
+
} else {
|
|
410
|
+
source = "overlay-only";
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const detachedReason = isLiveDetached
|
|
414
|
+
? ((liveAnchor as { reason?: ScopeDebugEntry["detachedReason"] }).reason ?? "deleted")
|
|
415
|
+
: source === "detached"
|
|
416
|
+
? "invalidatedByStructureChange"
|
|
417
|
+
: undefined;
|
|
418
|
+
|
|
419
|
+
const trusted = source === "marker-backed" || source === "overlay-only";
|
|
420
|
+
|
|
421
|
+
const location = safeCall(
|
|
422
|
+
runtime,
|
|
423
|
+
(r) => r.getLocationForAnchor(liveAnchor as never, overlayScope?.storyTarget),
|
|
424
|
+
null,
|
|
425
|
+
partialFallbacks,
|
|
426
|
+
`location-for-scope:${scopeId}`,
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
const warning = warningByScope.get(scopeId) ?? null;
|
|
430
|
+
|
|
431
|
+
const entry: ScopeDebugEntry = {
|
|
432
|
+
scopeId,
|
|
433
|
+
label: overlayScope?.label ?? queryResult?.scope.label,
|
|
434
|
+
mode: (liveScope?.mode ?? overlayScope?.mode ?? "comment") as ScopeDebugEntry["mode"],
|
|
435
|
+
visibility: (overlayScope?.visibility ?? "visible") as ScopeDebugEntry["visibility"],
|
|
436
|
+
storyTarget: overlayScope?.storyTarget ?? { kind: "main" },
|
|
437
|
+
source,
|
|
438
|
+
liveAnchor: liveAnchor as ScopeDebugEntry["liveAnchor"],
|
|
439
|
+
storedOverlayAnchor: overlayScope?.anchor ?? null,
|
|
440
|
+
trusted,
|
|
441
|
+
markerState,
|
|
442
|
+
...(detachedReason ? { detachedReason } : {}),
|
|
443
|
+
...(warning ? { warningId: warning.warningId } : {}),
|
|
444
|
+
...(isLiveDetached
|
|
445
|
+
? {
|
|
446
|
+
lastKnownRange: (liveAnchor as { lastKnownRange?: { from: number; to: number } })
|
|
447
|
+
.lastKnownRange,
|
|
448
|
+
}
|
|
449
|
+
: {}),
|
|
450
|
+
location,
|
|
451
|
+
...(overlayScope?.metadata && overlayScope.metadata.length > 0
|
|
452
|
+
? {
|
|
453
|
+
// F-15: iterate every metadata entry; previously we dropped entries
|
|
454
|
+
// past index 0, which broke scopes with multiple metadata refs.
|
|
455
|
+
metadataLookups: overlayScope.metadata.map((m) => ({
|
|
456
|
+
...(m?.key ? { metadataId: m.key } : {}),
|
|
457
|
+
...(m?.storageRef ? { storageRef: String(m.storageRef) } : {}),
|
|
458
|
+
...(m?.metadataVersion !== undefined
|
|
459
|
+
? { metadataVersion: m.metadataVersion }
|
|
460
|
+
: {}),
|
|
461
|
+
})),
|
|
462
|
+
}
|
|
463
|
+
: {}),
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
if (matchesScopeFilter(entry, scopeFilter)) {
|
|
467
|
+
entries.push(entry);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// F-8: sort by doc-order (first-marker start position) when the scope is
|
|
472
|
+
// marker-backed in the document. Overlay-only / detached scopes lack a
|
|
473
|
+
// live position; push them to the end and keep them deterministically
|
|
474
|
+
// ordered by scopeId. This matches the plan's "top-to-bottom traversal"
|
|
475
|
+
// assumption in doc-debug-stack.md §diagnostic isolation.
|
|
476
|
+
const positionOf = (scopeId: string): number | undefined =>
|
|
477
|
+
markerLocations.get(scopeId)?.startPos;
|
|
478
|
+
entries.sort((a, b) => {
|
|
479
|
+
const aPos = positionOf(a.scopeId);
|
|
480
|
+
const bPos = positionOf(b.scopeId);
|
|
481
|
+
if (aPos !== undefined && bPos !== undefined) return aPos - bPos;
|
|
482
|
+
if (aPos !== undefined) return -1;
|
|
483
|
+
if (bPos !== undefined) return 1;
|
|
484
|
+
return a.scopeId.localeCompare(b.scopeId);
|
|
485
|
+
});
|
|
486
|
+
return entries;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function projectWorkflow(
|
|
490
|
+
overlay: WorkflowOverlay | null,
|
|
491
|
+
scopes: readonly ScopeDebugEntry[],
|
|
492
|
+
runtimeForDebugEntry: DocumentRuntime | null,
|
|
493
|
+
fallbacks: string[],
|
|
494
|
+
): DebugInspectorWorkflowSection {
|
|
495
|
+
let markerBackedCount = 0;
|
|
496
|
+
let overlayOnlyCount = 0;
|
|
497
|
+
let detachedCount = 0;
|
|
498
|
+
for (const s of scopes) {
|
|
499
|
+
if (s.source === "marker-backed") markerBackedCount += 1;
|
|
500
|
+
else if (s.source === "overlay-only") overlayOnlyCount += 1;
|
|
501
|
+
else detachedCount += 1;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const base: DebugInspectorWorkflowSection = {
|
|
505
|
+
overlay,
|
|
506
|
+
activeWorkItemId: overlay?.activeWorkItemId ?? null,
|
|
507
|
+
metadataPersistenceMode: overlay?.metadataPersistence ?? null,
|
|
508
|
+
candidateCount: overlay?.candidates?.length ?? 0,
|
|
509
|
+
scopeCount: scopes.length,
|
|
510
|
+
markerBackedCount,
|
|
511
|
+
overlayOnlyCount,
|
|
512
|
+
detachedCount,
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
if (!runtimeForDebugEntry) return base;
|
|
516
|
+
|
|
517
|
+
const metadataSnapshot = safeCall(
|
|
518
|
+
runtimeForDebugEntry,
|
|
519
|
+
(r) => r.getWorkflowMetadataSnapshot(),
|
|
520
|
+
null,
|
|
521
|
+
fallbacks,
|
|
522
|
+
"workflow-metadata-snapshot",
|
|
523
|
+
);
|
|
524
|
+
const markupSnapshot = safeCall(
|
|
525
|
+
runtimeForDebugEntry,
|
|
526
|
+
(r) => r.getWorkflowMarkupSnapshot(),
|
|
527
|
+
null,
|
|
528
|
+
fallbacks,
|
|
529
|
+
"workflow-markup-snapshot",
|
|
530
|
+
);
|
|
531
|
+
const guard = safeCall(
|
|
532
|
+
runtimeForDebugEntry,
|
|
533
|
+
(r) => r.getInteractionGuardSnapshot(),
|
|
534
|
+
null,
|
|
535
|
+
fallbacks,
|
|
536
|
+
"interaction-guard-snapshot",
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
const debugEntry = projectWorkflowDebugEntry({
|
|
540
|
+
overlay,
|
|
541
|
+
metadataDefinitions: metadataSnapshot?.definitions ?? [],
|
|
542
|
+
metadataEntries: metadataSnapshot?.entries ?? [],
|
|
543
|
+
protectedRangeCount: markupSnapshot?.protectedRanges.length ?? 0,
|
|
544
|
+
scopeCounts: {
|
|
545
|
+
markerBacked: markerBackedCount,
|
|
546
|
+
overlayOnly: overlayOnlyCount,
|
|
547
|
+
detached: detachedCount,
|
|
548
|
+
},
|
|
549
|
+
guard,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
return { ...base, debugEntry };
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function projectReview(
|
|
556
|
+
runtime: DocumentRuntime,
|
|
557
|
+
fallbacks: string[],
|
|
558
|
+
): DebugInspectorReviewSection {
|
|
559
|
+
const render = safeCall(runtime, (r) => r.getRenderSnapshot(), null, fallbacks, "render-for-review");
|
|
560
|
+
const comments =
|
|
561
|
+
(render as { comments?: { openCommentIds?: string[]; detachedCommentIds?: string[] } } | null)
|
|
562
|
+
?.comments ?? null;
|
|
563
|
+
const tracked =
|
|
564
|
+
(render as {
|
|
565
|
+
trackedChanges?: { pendingChangeIds?: string[]; detachedChangeIds?: string[] };
|
|
566
|
+
} | null)?.trackedChanges ?? null;
|
|
567
|
+
return {
|
|
568
|
+
unresolvedCommentCount: comments?.openCommentIds?.length ?? 0,
|
|
569
|
+
pendingRevisionCount: tracked?.pendingChangeIds?.length ?? 0,
|
|
570
|
+
detachedCommentCount: comments?.detachedCommentIds?.length ?? 0,
|
|
571
|
+
detachedRevisionCount: tracked?.detachedChangeIds?.length ?? 0,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function projectLayout(
|
|
576
|
+
runtime: DocumentRuntime,
|
|
577
|
+
fallbacks: string[],
|
|
578
|
+
): DebugInspectorLayoutSection {
|
|
579
|
+
const pageLayout = safeCall(
|
|
580
|
+
runtime,
|
|
581
|
+
(r) => r.getPageLayoutSnapshot(),
|
|
582
|
+
null,
|
|
583
|
+
fallbacks,
|
|
584
|
+
"page-layout-summary",
|
|
585
|
+
);
|
|
586
|
+
const sections = safeCall(runtime, (r) => r.getSections(), [], fallbacks, "sections");
|
|
587
|
+
const stories = safeCall(
|
|
588
|
+
runtime,
|
|
589
|
+
(r) => r.getDocumentTextStream(),
|
|
590
|
+
[],
|
|
591
|
+
fallbacks,
|
|
592
|
+
"document-text-stream",
|
|
593
|
+
);
|
|
594
|
+
return {
|
|
595
|
+
pageCount: (pageLayout as { pages?: unknown[] } | null)?.pages?.length ?? null,
|
|
596
|
+
sectionCount: sections.length,
|
|
597
|
+
storyCount: stories.length,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* -------------------------------------------------------------------------- */
|
|
602
|
+
|
|
603
|
+
function deriveMarkerState(
|
|
604
|
+
marker: { startPos?: number; endPos?: number } | undefined,
|
|
605
|
+
): ScopeMarkerState {
|
|
606
|
+
if (!marker) return "missing";
|
|
607
|
+
const hasStart = marker.startPos !== undefined;
|
|
608
|
+
const hasEnd = marker.endPos !== undefined;
|
|
609
|
+
if (hasStart && hasEnd) return "complete";
|
|
610
|
+
if (hasStart) return "start-only";
|
|
611
|
+
if (hasEnd) return "end-only";
|
|
612
|
+
return "missing";
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function matchesScopeFilter(
|
|
616
|
+
entry: ScopeDebugEntry,
|
|
617
|
+
filter: DebugInspectorQuery["scopeFilter"],
|
|
618
|
+
): boolean {
|
|
619
|
+
if (!filter) return true;
|
|
620
|
+
if (filter.scopeIds && !filter.scopeIds.includes(entry.scopeId)) return false;
|
|
621
|
+
if (filter.modes && !filter.modes.includes(entry.mode)) return false;
|
|
622
|
+
if (filter.source) {
|
|
623
|
+
const allowed = Array.isArray(filter.source) ? filter.source : [filter.source];
|
|
624
|
+
if (!allowed.includes(entry.source)) return false;
|
|
625
|
+
}
|
|
626
|
+
if (filter.onlyDetached && entry.source !== "detached") return false;
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function safeCall<T>(
|
|
631
|
+
runtime: DocumentRuntime,
|
|
632
|
+
fn: (r: DocumentRuntime) => T,
|
|
633
|
+
fallback: T,
|
|
634
|
+
fallbacks: string[],
|
|
635
|
+
tag: string,
|
|
636
|
+
): T {
|
|
637
|
+
try {
|
|
638
|
+
return fn(runtime);
|
|
639
|
+
} catch (err) {
|
|
640
|
+
fallbacks.push(`${tag}:${(err as Error).message ?? "error"}`);
|
|
641
|
+
return fallback;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function safeGetDocument(
|
|
646
|
+
runtime: DocumentRuntime,
|
|
647
|
+
fallbacks: string[],
|
|
648
|
+
): CanonicalDocumentEnvelope | null {
|
|
649
|
+
return safeCall(
|
|
650
|
+
runtime,
|
|
651
|
+
(r) => r.getCanonicalDocument(),
|
|
652
|
+
null,
|
|
653
|
+
fallbacks,
|
|
654
|
+
"canonical-document",
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function extractFatalError(
|
|
659
|
+
runtime: DocumentRuntime,
|
|
660
|
+
fallbacks: string[],
|
|
661
|
+
): { code: string; message: string } | null {
|
|
662
|
+
const state = safeCall(
|
|
663
|
+
runtime,
|
|
664
|
+
(r) => r.getViewState() as { fatalError?: { code: string; message: string } | null },
|
|
665
|
+
null,
|
|
666
|
+
fallbacks,
|
|
667
|
+
"fatal-error",
|
|
668
|
+
);
|
|
669
|
+
return state?.fatalError ?? null;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// F-14: the previous implementation returned an ad-hoc shape silenced with
|
|
673
|
+
// `as never`. The real CompatibilityReport interface (see
|
|
674
|
+
// `src/api/public-types.ts`) requires reportVersion, generatedAt,
|
|
675
|
+
// blockExport, featureEntries, warnings, errors — all declared here so a
|
|
676
|
+
// downstream destructure doesn't throw on missing fields.
|
|
677
|
+
function emptyCompatibilityReport(): DebugInspectorHealthSection["compatibility"] {
|
|
678
|
+
return {
|
|
679
|
+
reportVersion: "compatibility-report/1",
|
|
680
|
+
generatedAt: new Date().toISOString(),
|
|
681
|
+
blockExport: false,
|
|
682
|
+
featureEntries: [],
|
|
683
|
+
warnings: [],
|
|
684
|
+
errors: [],
|
|
685
|
+
};
|
|
686
|
+
}
|