@beyondwork/docx-react-component 1.0.67 → 1.0.70
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 -932
- 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 -4797
- 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,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @endStateApi v3 — deterministic mock factories.
|
|
3
|
+
*
|
|
4
|
+
* Every mock payload carries `__mock: true`. Mocks are seeded from stable
|
|
5
|
+
* inputs (documentId, sha256, or a fixed counter) so BW consumer tests
|
|
6
|
+
* snapshot against deterministic shapes. Nothing here uses randomness.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { MockPayload } from "./_layer-metadata.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @endStateApi
|
|
13
|
+
* Tag a payload as a mock. Called by every mock-returning v3 function.
|
|
14
|
+
*
|
|
15
|
+
* Body is spread FIRST, then the markers — this guarantees that even if a
|
|
16
|
+
* caller accidentally passes a body with an `__mock`/`reason`/`shape` key,
|
|
17
|
+
* the markers win and the mock flag is never lost.
|
|
18
|
+
*/
|
|
19
|
+
export function mockPayload<T extends object>(
|
|
20
|
+
reason: string,
|
|
21
|
+
shape: string,
|
|
22
|
+
body: T,
|
|
23
|
+
): T & MockPayload {
|
|
24
|
+
return {
|
|
25
|
+
...body,
|
|
26
|
+
__mock: true,
|
|
27
|
+
reason,
|
|
28
|
+
shape,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @endStateApi
|
|
34
|
+
* Tag an ARRAY payload as a mock. `mockPayload` uses object spread which
|
|
35
|
+
* collapses arrays to plain objects (loses Array-ness). Use this for
|
|
36
|
+
* functions whose return type is `ReadonlyArray<T>` — it attaches the
|
|
37
|
+
* markers as non-indexed properties so `Array.isArray` still returns true
|
|
38
|
+
* AND `isMock` narrows correctly.
|
|
39
|
+
*/
|
|
40
|
+
export function mockArray<T>(
|
|
41
|
+
reason: string,
|
|
42
|
+
shape: string,
|
|
43
|
+
items: readonly T[],
|
|
44
|
+
): readonly T[] & MockPayload {
|
|
45
|
+
const arr = items.slice() as T[];
|
|
46
|
+
return Object.assign(arr, {
|
|
47
|
+
__mock: true as const,
|
|
48
|
+
reason,
|
|
49
|
+
shape,
|
|
50
|
+
}) as readonly T[] & MockPayload;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @endStateApi
|
|
55
|
+
* Derive a stable string from a seed + name. Used where a mock needs an
|
|
56
|
+
* ID-shaped value (e.g. scopeId for a mock createScope call).
|
|
57
|
+
*/
|
|
58
|
+
export function mockId(seed: string, name: string): string {
|
|
59
|
+
// Simple deterministic mix — not cryptographic; just stable across runs.
|
|
60
|
+
let h = 0;
|
|
61
|
+
const input = `${seed}::${name}`;
|
|
62
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
63
|
+
h = (h * 31 + input.charCodeAt(i)) | 0;
|
|
64
|
+
}
|
|
65
|
+
// `h >>> 0` coerces the 32-bit signed int to unsigned so base36 never
|
|
66
|
+
// produces a negative-prefixed string (edge case: h === -2^31 where
|
|
67
|
+
// Math.abs would still return negative).
|
|
68
|
+
const hex = (h >>> 0).toString(36).padStart(8, "0");
|
|
69
|
+
return `mock-${name}-${hex}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @endStateApi
|
|
74
|
+
* Return `true` iff the argument carries the mock flag. Consumer tests
|
|
75
|
+
* can narrow via this guard: `if (isMock(result)) { ... }`.
|
|
76
|
+
*/
|
|
77
|
+
export function isMock(value: unknown): value is MockPayload {
|
|
78
|
+
return (
|
|
79
|
+
typeof value === "object" &&
|
|
80
|
+
value !== null &&
|
|
81
|
+
(value as { __mock?: unknown }).__mock === true
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @endStateApi v3 — `RuntimeApiHandle`.
|
|
3
|
+
*
|
|
4
|
+
* The narrow interface v3 family modules type against. It enumerates the
|
|
5
|
+
* exact runtime surface v3 reads — nothing more. Family modules accept a
|
|
6
|
+
* `RuntimeApiHandle` instead of a full `DocumentRuntime`, which:
|
|
7
|
+
*
|
|
8
|
+
* 1. Removes the `(runtime as unknown as { ... })` casts that previously
|
|
9
|
+
* asserted facet shape from inside each family module.
|
|
10
|
+
* 2. Enables headless callers (tests, debug harness, stateless services)
|
|
11
|
+
* to satisfy the v3 API with a minimal stub — no full runtime needed.
|
|
12
|
+
* 3. Makes the v3 dependency surface auditable: any v3 code that reaches
|
|
13
|
+
* a method not on this interface is a compile error.
|
|
14
|
+
*
|
|
15
|
+
* The interface is defined as `Pick<DocumentRuntime, ...>` so the member
|
|
16
|
+
* types stay in lockstep with the authoritative runtime interface. If a
|
|
17
|
+
* runtime method signature changes, v3 breaks at the consumption site
|
|
18
|
+
* rather than silently drifting.
|
|
19
|
+
*
|
|
20
|
+
* Geometry note: `handle.geometry` is the `GeometryFacet` constructed by
|
|
21
|
+
* `document-runtime.ts` against the shared render kernel. v3's
|
|
22
|
+
* `runtime.geometry` family reads through `handle.geometry` — the prior
|
|
23
|
+
* "reach geometry through `handle.layout`" shim was removed in the
|
|
24
|
+
* refactor/05 adversarial-closure pass once the runtime exposed the facet
|
|
25
|
+
* directly.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type { DocumentRuntime } from "../../runtime/document-runtime.ts";
|
|
29
|
+
import type { CollabSession } from "../../runtime/collab-session.ts";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @endStateApi
|
|
33
|
+
* Narrow runtime surface consumed by v3 family modules. Structurally a
|
|
34
|
+
* subset of `DocumentRuntime`; any `DocumentRuntime` satisfies it.
|
|
35
|
+
*
|
|
36
|
+
* Optional members (declared via intersection after the Pick) expose
|
|
37
|
+
* surfaces the runtime does not own directly but hosts can wire in —
|
|
38
|
+
* `collabSession` is the first such member, letting v3's
|
|
39
|
+
* `runtime.collab.*` family graduate its live path when hosts supply it
|
|
40
|
+
* and fall back to deterministic mocks when they don't.
|
|
41
|
+
*/
|
|
42
|
+
export type RuntimeApiHandle = Pick<
|
|
43
|
+
DocumentRuntime,
|
|
44
|
+
// Session + export (runtime.document family)
|
|
45
|
+
| "getSessionState"
|
|
46
|
+
| "exportDocx"
|
|
47
|
+
| "getCompatibilityReport"
|
|
48
|
+
| "getWarnings"
|
|
49
|
+
| "getRenderSnapshot"
|
|
50
|
+
// Canonical document read (ai.inspect + ai.bundle + ai.resolve families,
|
|
51
|
+
// added in refactor/08 Slice 2/3 graduations)
|
|
52
|
+
| "getCanonicalDocument"
|
|
53
|
+
// Content search + selection (runtime.content + ai.bundle families)
|
|
54
|
+
| "findAllText"
|
|
55
|
+
// Review (runtime.review family)
|
|
56
|
+
| "getReviewWorkSnapshot"
|
|
57
|
+
| "acceptChange"
|
|
58
|
+
| "resolveComment"
|
|
59
|
+
// Workflow (runtime.workflow + ai.inspect families)
|
|
60
|
+
| "queryScopes"
|
|
61
|
+
| "getWorkflowMarkupSnapshot"
|
|
62
|
+
| "getInteractionGuardSnapshot"
|
|
63
|
+
| "getWorkflowOverlay"
|
|
64
|
+
// Workflow writers (runtime.workflow.createScope + attachMetadata
|
|
65
|
+
// graduations, Layer-06 Slice 3). The handle must expose the
|
|
66
|
+
// pipeline each adapter dispatches through, or v3 cannot be a real
|
|
67
|
+
// live seam. `getWorkflowMetadataSnapshot` is the read side the
|
|
68
|
+
// metadata writer inspects before merging its entry.
|
|
69
|
+
| "addScope"
|
|
70
|
+
| "setWorkflowMetadataEntries"
|
|
71
|
+
| "getWorkflowMetadataSnapshot"
|
|
72
|
+
// W10 overlay-visibility policy (state-classes X1). Class-A canonical
|
|
73
|
+
// state; L06 owns read + write, L10 composes with local preference.
|
|
74
|
+
| "getVisibilityPolicy"
|
|
75
|
+
| "getVisibilityPolicies"
|
|
76
|
+
| "setVisibilityPolicy"
|
|
77
|
+
| "clearVisibilityPolicy"
|
|
78
|
+
| "subscribeVisibilityPolicy"
|
|
79
|
+
// X5 class-A markup-mode policy (state-classes X5).
|
|
80
|
+
| "getMarkupModePolicy"
|
|
81
|
+
| "setMarkupModePolicy"
|
|
82
|
+
| "subscribeMarkupModePolicy"
|
|
83
|
+
// Scope lookup (runtime.content.getLocation — replaced the debug-facet
|
|
84
|
+
// escape-hatch path with a typed scope + anchor read)
|
|
85
|
+
| "getScope"
|
|
86
|
+
| "getLocationForAnchor"
|
|
87
|
+
// Layer-10 `ui.scope.*` enabler (coord-07 §2.7 / coord-10 §α). L10's
|
|
88
|
+
// layer-purity guard blocks `src/runtime/scopes/**` + `src/api/v3/ai/**`,
|
|
89
|
+
// so L10 cannot construct its own scope compiler or call ai.getScopeBundle.
|
|
90
|
+
// Exposing this scopeId-keyed compile primitive on the handle lets
|
|
91
|
+
// `ui/scope.ts` deliver `SemanticScope` / `ScopeBundle` reads directly.
|
|
92
|
+
| "compileScopeBundleById"
|
|
93
|
+
// Layer-08 Slice-5 — scope-scoped replacement dispatch. `ai.apply
|
|
94
|
+
// ReplacementScope` + `runtime.content.replaceText(scopeId, …)`
|
|
95
|
+
// route compiled plans through this seam.
|
|
96
|
+
| "applyScopeReplacement"
|
|
97
|
+
// Nested facets (runtime.layout + runtime.geometry families,
|
|
98
|
+
// plus debug telemetry bus for UxResponse emission)
|
|
99
|
+
| "debug"
|
|
100
|
+
| "layout"
|
|
101
|
+
| "geometry"
|
|
102
|
+
> & {
|
|
103
|
+
/**
|
|
104
|
+
* Optional collab session — hosts that wire Yjs/Awareness pass the
|
|
105
|
+
* session here so `api.runtime.collab.getPresence` / `.getPosture`
|
|
106
|
+
* can delegate live. When absent, those functions return
|
|
107
|
+
* deterministic mock snapshots (peers: [], posture: unattached).
|
|
108
|
+
*/
|
|
109
|
+
readonly collabSession?: CollabSession;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @endStateApi
|
|
114
|
+
* Compile-time drift guard. This object's type is
|
|
115
|
+
* `Record<keyof RuntimeApiHandle, true>`, so adding a member to the
|
|
116
|
+
* interface without adding a key here — or removing a member without
|
|
117
|
+
* dropping the key — fails `pnpm run lint:tsgo` before it can land.
|
|
118
|
+
*
|
|
119
|
+
* `test/api/v3/runtime-handle-shape.test.ts` imports this constant and
|
|
120
|
+
* asserts at runtime that its key set equals the explicit audit roster
|
|
121
|
+
* maintained there. The two checks together catch both interface drift
|
|
122
|
+
* (this file, via tsgo) and audit-list drift (the test, via node:test).
|
|
123
|
+
*/
|
|
124
|
+
export const RUNTIME_API_HANDLE_SHAPE_CHECK: Record<keyof RuntimeApiHandle, true> = {
|
|
125
|
+
getSessionState: true,
|
|
126
|
+
exportDocx: true,
|
|
127
|
+
getCompatibilityReport: true,
|
|
128
|
+
getWarnings: true,
|
|
129
|
+
getRenderSnapshot: true,
|
|
130
|
+
getCanonicalDocument: true,
|
|
131
|
+
findAllText: true,
|
|
132
|
+
getReviewWorkSnapshot: true,
|
|
133
|
+
acceptChange: true,
|
|
134
|
+
resolveComment: true,
|
|
135
|
+
queryScopes: true,
|
|
136
|
+
getWorkflowMarkupSnapshot: true,
|
|
137
|
+
getInteractionGuardSnapshot: true,
|
|
138
|
+
getWorkflowOverlay: true,
|
|
139
|
+
addScope: true,
|
|
140
|
+
setWorkflowMetadataEntries: true,
|
|
141
|
+
getWorkflowMetadataSnapshot: true,
|
|
142
|
+
getVisibilityPolicy: true,
|
|
143
|
+
getVisibilityPolicies: true,
|
|
144
|
+
setVisibilityPolicy: true,
|
|
145
|
+
clearVisibilityPolicy: true,
|
|
146
|
+
subscribeVisibilityPolicy: true,
|
|
147
|
+
getMarkupModePolicy: true,
|
|
148
|
+
setMarkupModePolicy: true,
|
|
149
|
+
subscribeMarkupModePolicy: true,
|
|
150
|
+
getScope: true,
|
|
151
|
+
getLocationForAnchor: true,
|
|
152
|
+
compileScopeBundleById: true,
|
|
153
|
+
applyScopeReplacement: true,
|
|
154
|
+
debug: true,
|
|
155
|
+
layout: true,
|
|
156
|
+
geometry: true,
|
|
157
|
+
// Optional members participate in the drift guard too — they're keys
|
|
158
|
+
// of the full RuntimeApiHandle type, so omitting them here would not
|
|
159
|
+
// fail `Record<keyof ...>`. Included explicitly so additions are
|
|
160
|
+
// visible in this single audit roster.
|
|
161
|
+
collabSession: true,
|
|
162
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @endStateApi v3 — UX-response event contract.
|
|
3
|
+
*
|
|
4
|
+
* Every v3 function whose metadata declares `uxIntent.uiVisible === true`
|
|
5
|
+
* MUST call `emitUxResponse(runtime, res)` exactly once per invocation.
|
|
6
|
+
* The response is published on the existing `api` telemetry channel with
|
|
7
|
+
* `type: "ux.response.<apiFn>"`. Phase Q's debug UX subscribes to these to
|
|
8
|
+
* render mock-or-live visual traces identically.
|
|
9
|
+
*
|
|
10
|
+
* Unit tests assert the one-emit-per-call invariant. The
|
|
11
|
+
* `ci-check-api-v3-metadata` guard cross-checks that every function with
|
|
12
|
+
* `uiVisible: true` in its metadata has a corresponding `emitUxResponse`
|
|
13
|
+
* call in its implementation body.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { RuntimeApiHandle } from "./_runtime-handle.ts";
|
|
17
|
+
import type { ApiStatus, UxIntent } from "./_layer-metadata.ts";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @endStateApi
|
|
21
|
+
* UX event envelope. `intent`/`expectedDelta` come from the function's
|
|
22
|
+
* metadata and describe what the UI should render if the operation is
|
|
23
|
+
* live. `actualDelta` is populated only on the live path.
|
|
24
|
+
*/
|
|
25
|
+
export interface UxResponse {
|
|
26
|
+
readonly apiFn: string;
|
|
27
|
+
readonly intent: string;
|
|
28
|
+
readonly mockOrLive: ApiStatus;
|
|
29
|
+
readonly uiVisible: boolean;
|
|
30
|
+
readonly expectedDelta?: string;
|
|
31
|
+
readonly actualDelta?: {
|
|
32
|
+
readonly kind: NonNullable<UxIntent["expectsUxResponse"]>;
|
|
33
|
+
readonly payload: unknown;
|
|
34
|
+
};
|
|
35
|
+
readonly auditHints?: readonly string[];
|
|
36
|
+
readonly ts: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @endStateApi
|
|
41
|
+
* Publish a UxResponse on the runtime's `api` telemetry channel. Safe to
|
|
42
|
+
* call when the channel is off — the bus bitmap gate short-circuits
|
|
43
|
+
* before any allocation. Returns nothing; fire-and-forget.
|
|
44
|
+
*
|
|
45
|
+
* Defensive posture: when the handle does not carry a telemetry bus
|
|
46
|
+
* (headless stubs, test doubles that exercise UI dispatch logic without
|
|
47
|
+
* wiring telemetry), this function silently no-ops instead of throwing.
|
|
48
|
+
* Production `DocumentRuntime` always supplies `runtime.debug.bus`;
|
|
49
|
+
* test handles may choose not to. A missing bus is NOT a contract
|
|
50
|
+
* violation — it's an opt-out of telemetry observation, not of the
|
|
51
|
+
* dispatch/subscribe behaviour itself.
|
|
52
|
+
*/
|
|
53
|
+
export function emitUxResponse(
|
|
54
|
+
runtime: RuntimeApiHandle,
|
|
55
|
+
res: Omit<UxResponse, "ts">,
|
|
56
|
+
): void {
|
|
57
|
+
const bus = runtime.debug?.bus;
|
|
58
|
+
if (!bus || typeof bus.emit !== "function") return;
|
|
59
|
+
const stamped: UxResponse = { ...res, ts: performanceNow() };
|
|
60
|
+
bus.emit({
|
|
61
|
+
channel: "api",
|
|
62
|
+
type: `ux.response.${res.apiFn}`,
|
|
63
|
+
t: 0,
|
|
64
|
+
payload: stamped as unknown as Record<string, unknown>,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function performanceNow(): number {
|
|
69
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
70
|
+
return performance.now();
|
|
71
|
+
}
|
|
72
|
+
return Date.now();
|
|
73
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @endStateApi v3 — metadata-write audit emitter.
|
|
3
|
+
*
|
|
4
|
+
* Architecture 09 §A4: every mutating function emits exactly one
|
|
5
|
+
* `ScopeActionAudit` record. `applyReplacementScope` emits via the
|
|
6
|
+
* /08 scope-compiler's `emitScopeActionAudit` on the replacement path.
|
|
7
|
+
* `attachExplanation` and `createIssue` are mutating (scope-metadata
|
|
8
|
+
* writes) but do not route through the replacement lifecycle — they
|
|
9
|
+
* need their own audit emission that reuses the `ScopeActionAudit`
|
|
10
|
+
* shape with `operation: "annotate"`.
|
|
11
|
+
*
|
|
12
|
+
* This module is the single place that constructs those audit records
|
|
13
|
+
* for /09's metadata writes, so the shape + emission site stay honest
|
|
14
|
+
* and discoverable from one file.
|
|
15
|
+
*
|
|
16
|
+
* Design notes:
|
|
17
|
+
*
|
|
18
|
+
* 1. We reuse the `ScopeActionAudit` shape exactly — no new type.
|
|
19
|
+
* The `ReplacementScope.operation: "annotate"` variant already
|
|
20
|
+
* exists in the taxonomy for this case; metadata writes fill it
|
|
21
|
+
* with a synthesized `ReplacementScope` carrying structured
|
|
22
|
+
* payload describing the attached explanation / created issue.
|
|
23
|
+
*
|
|
24
|
+
* 2. The helper compiles the target scope fresh before emission —
|
|
25
|
+
* the snapshot captures the scope state AFTER the primitive
|
|
26
|
+
* returned, which is the post-mutation canonical truth.
|
|
27
|
+
*
|
|
28
|
+
* 3. `validation` is synthesized as a `safe: true, blockedReasons:[],
|
|
29
|
+
* warnings: []` record. Metadata writes currently bypass the
|
|
30
|
+
* unified action-validation contract (Layer 08 Slice 4 shape);
|
|
31
|
+
* when /06 ships the workflow-metadata policy-gating pass, this
|
|
32
|
+
* emitter upgrades to route through composeScopeValidation too.
|
|
33
|
+
*
|
|
34
|
+
* 4. `documentHash` is a local copy of the same block-count + text-
|
|
35
|
+
* length structural hash used by the replacement path so
|
|
36
|
+
* before/after signatures stay comparable across audit types.
|
|
37
|
+
* When /08 promotes `documentHash` to a public export the two
|
|
38
|
+
* copies collapse to one.
|
|
39
|
+
*
|
|
40
|
+
* 5. Errors in the emitter MUST NOT propagate. The primitive's
|
|
41
|
+
* write has already committed; the audit is a telemetry side-
|
|
42
|
+
* effect. Failure here is logged on the `commit` channel (per
|
|
43
|
+
* CLAUDE.md's "never break the edit path" discipline) and
|
|
44
|
+
* swallowed.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
import type { RuntimeApiHandle } from "../_runtime-handle.ts";
|
|
48
|
+
import type { CanonicalDocumentEnvelope } from "../../../core/state/editor-state.ts";
|
|
49
|
+
import {
|
|
50
|
+
buildParagraphIndexMap,
|
|
51
|
+
compileScope,
|
|
52
|
+
enumerateScopes,
|
|
53
|
+
type ReplacementOperationKind,
|
|
54
|
+
type ReplacementScope,
|
|
55
|
+
type ScopeActionAudit,
|
|
56
|
+
type SemanticScope,
|
|
57
|
+
type ValidationResult,
|
|
58
|
+
} from "../../../runtime/scopes/index.ts";
|
|
59
|
+
|
|
60
|
+
export interface EmitMetadataAuditInputs {
|
|
61
|
+
readonly runtime: RuntimeApiHandle;
|
|
62
|
+
/**
|
|
63
|
+
* API function name in dotted form (e.g. `"ai.attachExplanation"`).
|
|
64
|
+
* Used as the audit's `actionId`.
|
|
65
|
+
*/
|
|
66
|
+
readonly actionId: string;
|
|
67
|
+
/** `"ui" | "agent" | "host"` — default `"agent"` when omitted. */
|
|
68
|
+
readonly origin?: "ui" | "agent" | "host";
|
|
69
|
+
/** Actor id — default `"v3-ai-api"` when omitted. */
|
|
70
|
+
readonly actorId?: string;
|
|
71
|
+
/** ScopeId of the write target. */
|
|
72
|
+
readonly scopeId: string;
|
|
73
|
+
/**
|
|
74
|
+
* Pre-mutation scope snapshot. The caller captures this BEFORE running
|
|
75
|
+
* the primitive — post-mutation the scope's text / formatting may have
|
|
76
|
+
* shifted (common when a same-session replacement just ran against the
|
|
77
|
+
* same target) and a fresh compile can miss. When the caller cannot
|
|
78
|
+
* produce a snapshot (e.g. the scope did not enumerate before the
|
|
79
|
+
* write), the audit is skipped silently.
|
|
80
|
+
*/
|
|
81
|
+
readonly targetScopeSnapshot: SemanticScope;
|
|
82
|
+
/**
|
|
83
|
+
* Structured payload describing what was attached. Surfaced in the
|
|
84
|
+
* audit's `proposed.proposedContent.structured` field.
|
|
85
|
+
*/
|
|
86
|
+
readonly proposedContent: {
|
|
87
|
+
readonly kind: "explanation" | "issue";
|
|
88
|
+
readonly payload: Record<string, unknown>;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Single-step `compiledOperations` entry kind. Distinct from the
|
|
92
|
+
* replacement-path kinds (`text-replace`, etc.) so audit consumers
|
|
93
|
+
* can narrow by `step.kind`.
|
|
94
|
+
*/
|
|
95
|
+
readonly compiledOperationKind: "metadata-attach-explanation" | "metadata-attach-issue";
|
|
96
|
+
/** Short description of the write — surfaced on `compiledOperations[0].summary`. */
|
|
97
|
+
readonly compiledOperationSummary: string;
|
|
98
|
+
/** Pin for determinism — callers pass a fixed value in tests. */
|
|
99
|
+
readonly emittedAtUtc: string;
|
|
100
|
+
/** Document hash snapshot BEFORE the primitive ran. Captured by the caller. */
|
|
101
|
+
readonly documentHashBefore: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function structuralDocumentHash(doc: CanonicalDocumentEnvelope): string {
|
|
105
|
+
// Same shape as /08's `documentHash` in replacement/apply.ts — local
|
|
106
|
+
// copy until /08 promotes that helper to a public export.
|
|
107
|
+
const root = doc.content;
|
|
108
|
+
let textLength = 0;
|
|
109
|
+
for (const block of root.children) {
|
|
110
|
+
if (block.type === "paragraph") {
|
|
111
|
+
for (const child of block.children) {
|
|
112
|
+
if (child.type === "text") textLength += child.text.length;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return `blocks:${root.children.length}|text:${textLength}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function compileScopeSnapshot(
|
|
120
|
+
runtime: RuntimeApiHandle,
|
|
121
|
+
scopeId: string,
|
|
122
|
+
): SemanticScope | null {
|
|
123
|
+
const doc = runtime.getCanonicalDocument();
|
|
124
|
+
const overlay = runtime.getWorkflowOverlay();
|
|
125
|
+
const paragraphIndexByBlockIndex = buildParagraphIndexMap(doc);
|
|
126
|
+
for (const entry of enumerateScopes(doc, overlay ? { overlay } : {})) {
|
|
127
|
+
if (entry.handle.scopeId !== scopeId) continue;
|
|
128
|
+
const compiled = compileScope(entry, {
|
|
129
|
+
document: doc,
|
|
130
|
+
...(overlay ? { overlay } : {}),
|
|
131
|
+
paragraphIndexByBlockIndex,
|
|
132
|
+
});
|
|
133
|
+
if (compiled) return compiled;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function snapshotDocumentHash(runtime: RuntimeApiHandle): string {
|
|
139
|
+
return structuralDocumentHash(
|
|
140
|
+
runtime.getCanonicalDocument() as CanonicalDocumentEnvelope,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Build + emit one `ScopeActionAudit` on the `scope` telemetry channel
|
|
146
|
+
* for a metadata-write (attachExplanation / createIssue). Returns the
|
|
147
|
+
* emitted audit so callers can surface it on their result.
|
|
148
|
+
*
|
|
149
|
+
* Never throws — telemetry failures are swallowed.
|
|
150
|
+
*/
|
|
151
|
+
/**
|
|
152
|
+
* Pre-mutation snapshot helper. Caller composes `captureScopeSnapshot`
|
|
153
|
+
* + primitive-write + `emitScopeMetadataAudit({targetScopeSnapshot})`
|
|
154
|
+
* so the snapshot reflects the state the write targeted, not the
|
|
155
|
+
* possibly-shifted post-mutation state.
|
|
156
|
+
*/
|
|
157
|
+
export function captureScopeSnapshot(
|
|
158
|
+
runtime: RuntimeApiHandle,
|
|
159
|
+
scopeId: string,
|
|
160
|
+
): SemanticScope | null {
|
|
161
|
+
return compileScopeSnapshot(runtime, scopeId);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function emitScopeMetadataAudit(
|
|
165
|
+
inputs: EmitMetadataAuditInputs,
|
|
166
|
+
): ScopeActionAudit | null {
|
|
167
|
+
try {
|
|
168
|
+
const snapshot = inputs.targetScopeSnapshot;
|
|
169
|
+
const operation: ReplacementOperationKind = "annotate";
|
|
170
|
+
const proposed: ReplacementScope = {
|
|
171
|
+
targetHandle: snapshot.handle,
|
|
172
|
+
operation,
|
|
173
|
+
proposedContent: {
|
|
174
|
+
kind: "structured",
|
|
175
|
+
structured: {
|
|
176
|
+
metadataKind: inputs.proposedContent.kind,
|
|
177
|
+
...inputs.proposedContent.payload,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
proposedAtUtc: inputs.emittedAtUtc,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const validation: ValidationResult = {
|
|
184
|
+
safe: true,
|
|
185
|
+
blockedReasons: [],
|
|
186
|
+
warnings: [],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// We build + emit the audit inline rather than going through
|
|
190
|
+
// `/08`'s `emitScopeActionAudit(plan)` helper because the helper
|
|
191
|
+
// reads `plan.steps[].kind` as a narrow `RuntimeOperationStepKind`
|
|
192
|
+
// union (`text-replace | … | fragment-replace`). Metadata writes
|
|
193
|
+
// need distinct op kinds (`metadata-attach-explanation`, etc.) that
|
|
194
|
+
// aren't in the replacement-path taxonomy and shouldn't be — they
|
|
195
|
+
// are not runtime operations in the replacement sense. The audit's
|
|
196
|
+
// downstream `compiledOperations[].kind` field is typed `string`,
|
|
197
|
+
// so emitting a metadata-specific value here is shape-compatible.
|
|
198
|
+
const audit: ScopeActionAudit = {
|
|
199
|
+
actionId: inputs.actionId,
|
|
200
|
+
actorId: inputs.actorId ?? "v3-ai-api",
|
|
201
|
+
origin: inputs.origin ?? "agent",
|
|
202
|
+
documentHashBefore: inputs.documentHashBefore,
|
|
203
|
+
documentHashAfter: snapshotDocumentHash(inputs.runtime),
|
|
204
|
+
targetScopeSnapshot: snapshot,
|
|
205
|
+
proposed,
|
|
206
|
+
compiledOperations: Object.freeze([
|
|
207
|
+
{
|
|
208
|
+
kind: inputs.compiledOperationKind,
|
|
209
|
+
summary: inputs.compiledOperationSummary,
|
|
210
|
+
},
|
|
211
|
+
]),
|
|
212
|
+
validation,
|
|
213
|
+
emittedAtUtc: inputs.emittedAtUtc,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
inputs.runtime.debug?.bus.emitLazy("scope", () => ({
|
|
217
|
+
type: "scope.action_audit",
|
|
218
|
+
payload: audit,
|
|
219
|
+
}));
|
|
220
|
+
return audit;
|
|
221
|
+
} catch {
|
|
222
|
+
// Audit is a side-effect; never break the edit path.
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|