@beyondwork/docx-react-component 1.0.58 → 1.0.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +2 -2
  2. package/package.json +2 -1
  3. package/src/api/awareness-identity-types.ts +4 -2
  4. package/src/api/comment-negotiation-types.ts +4 -1
  5. package/src/api/external-custody-types.ts +16 -0
  6. package/src/api/internal/build-ref-projections.ts +108 -0
  7. package/src/api/package-version.ts +1 -1
  8. package/src/api/participants-types.ts +11 -1
  9. package/src/api/public-types.ts +980 -10
  10. package/src/api/scope-metadata-resolver-types.ts +6 -0
  11. package/src/compare/diff-engine.ts +3 -0
  12. package/src/core/commands/formatting-commands.ts +1 -0
  13. package/src/core/commands/index.ts +225 -16
  14. package/src/core/commands/legacy-form-field-commands.ts +181 -0
  15. package/src/core/commands/table-structure-commands.ts +149 -31
  16. package/src/core/selection/mapping.ts +20 -0
  17. package/src/core/state/editor-state.ts +4 -1
  18. package/src/index.ts +28 -0
  19. package/src/io/docx-session.ts +22 -3
  20. package/src/io/export/export-session.ts +11 -7
  21. package/src/io/export/ooxml-namespaces.ts +47 -0
  22. package/src/io/export/reattach-preserved-parts.ts +4 -16
  23. package/src/io/export/serialize-comments.ts +3 -131
  24. package/src/io/export/serialize-ffdata.ts +89 -0
  25. package/src/io/export/serialize-headers-footers.ts +5 -0
  26. package/src/io/export/serialize-main-document.ts +224 -34
  27. package/src/io/export/serialize-numbering.ts +22 -2
  28. package/src/io/export/serialize-revisions.ts +99 -0
  29. package/src/io/export/serialize-tables.ts +9 -0
  30. package/src/io/export/split-review-boundaries.ts +1 -0
  31. package/src/io/export/table-properties-xml.ts +14 -0
  32. package/src/io/load-scheduler.ts +70 -28
  33. package/src/io/normalize/normalize-text.ts +13 -0
  34. package/src/io/ooxml/_mini-xml.ts +198 -0
  35. package/src/io/ooxml/canonicalize-payload.ts +1 -4
  36. package/src/io/ooxml/chart/chart-style-table.ts +4 -3
  37. package/src/io/ooxml/chart/parse-chart-space.ts +2 -4
  38. package/src/io/ooxml/chart/parse-series.ts +2 -1
  39. package/src/io/ooxml/chart/resolve-color.ts +2 -2
  40. package/src/io/ooxml/chart/types.ts +6 -434
  41. package/src/io/ooxml/comment-presentation-payload.ts +6 -5
  42. package/src/io/ooxml/highlight-colors.ts +8 -5
  43. package/src/io/ooxml/parse-anchor.ts +68 -53
  44. package/src/io/ooxml/parse-comments.ts +14 -142
  45. package/src/io/ooxml/parse-complex-content.ts +3 -106
  46. package/src/io/ooxml/parse-drawing.ts +100 -195
  47. package/src/io/ooxml/parse-ffdata.ts +93 -0
  48. package/src/io/ooxml/parse-fields.ts +7 -146
  49. package/src/io/ooxml/parse-fill.ts +88 -8
  50. package/src/io/ooxml/parse-font-table.ts +5 -105
  51. package/src/io/ooxml/parse-footnotes.ts +28 -152
  52. package/src/io/ooxml/parse-headers-footers.ts +106 -212
  53. package/src/io/ooxml/parse-inline-media.ts +3 -200
  54. package/src/io/ooxml/parse-main-document.ts +180 -217
  55. package/src/io/ooxml/parse-numbering.ts +154 -335
  56. package/src/io/ooxml/parse-object.ts +147 -0
  57. package/src/io/ooxml/parse-ole-relationship.ts +82 -0
  58. package/src/io/ooxml/parse-paragraph-formatting.ts +7 -10
  59. package/src/io/ooxml/parse-picture-sdt.ts +85 -0
  60. package/src/io/ooxml/parse-picture.ts +72 -42
  61. package/src/io/ooxml/parse-revisions.ts +285 -51
  62. package/src/io/ooxml/parse-settings.ts +6 -99
  63. package/src/io/ooxml/parse-shapes.ts +25 -140
  64. package/src/io/ooxml/parse-styles.ts +3 -218
  65. package/src/io/ooxml/parse-tables.ts +76 -256
  66. package/src/io/ooxml/parse-theme.ts +1 -4
  67. package/src/io/ooxml/property-grab-bag.ts +5 -47
  68. package/src/io/ooxml/workflow-payload.ts +6 -1
  69. package/src/io/ooxml/xml-element-serialize.ts +32 -0
  70. package/src/io/ooxml/xml-parser.ts +183 -0
  71. package/src/legal/bookmarks.ts +1 -1
  72. package/src/legal/cross-references.ts +1 -1
  73. package/src/legal/defined-terms.ts +1 -1
  74. package/src/legal/{_document-root.ts → document-root.ts} +8 -0
  75. package/src/legal/signature-blocks.ts +1 -1
  76. package/src/model/canonical-document.ts +159 -6
  77. package/src/model/chart-types.ts +439 -0
  78. package/src/model/snapshot.ts +5 -1
  79. package/src/review/store/comment-remapping.ts +24 -11
  80. package/src/review/store/revision-actions.ts +482 -2
  81. package/src/review/store/revision-store.ts +15 -0
  82. package/src/review/store/revision-types.ts +76 -0
  83. package/src/runtime/collab/remote-cursor-awareness.ts +24 -0
  84. package/src/runtime/collab/runtime-collab-sync.ts +33 -0
  85. package/src/runtime/diagnostics/build-diagnostic.ts +153 -0
  86. package/src/runtime/diagnostics/code-metadata-table.ts +230 -0
  87. package/src/runtime/document-runtime.ts +821 -54
  88. package/src/runtime/document-search.ts +115 -0
  89. package/src/runtime/edit-ops/index.ts +18 -2
  90. package/src/runtime/footnote-resolver.ts +130 -0
  91. package/src/runtime/layout/layout-engine-instance.ts +31 -4
  92. package/src/runtime/layout/layout-engine-version.ts +37 -1
  93. package/src/runtime/layout/page-graph.ts +14 -1
  94. package/src/runtime/layout/resolved-formatting-state.ts +21 -0
  95. package/src/runtime/numbering-prefix.ts +17 -0
  96. package/src/runtime/query-scopes.ts +108 -10
  97. package/src/runtime/resolved-numbering-geometry.ts +37 -6
  98. package/src/runtime/revision-runtime.ts +27 -1
  99. package/src/runtime/selection/post-edit-validator.ts +60 -6
  100. package/src/runtime/structure-ops/index.ts +20 -4
  101. package/src/runtime/surface-projection.ts +290 -21
  102. package/src/runtime/table-schema.ts +6 -0
  103. package/src/runtime/theme-color-resolver.ts +2 -2
  104. package/src/runtime/units.ts +9 -0
  105. package/src/runtime/workflow-rail-segments.ts +4 -0
  106. package/src/ui/WordReviewEditor.tsx +187 -43
  107. package/src/ui/editor-runtime-boundary.ts +10 -0
  108. package/src/ui/editor-shell-view.tsx +4 -1
  109. package/src/ui/headless/chrome-registry.ts +53 -0
  110. package/src/ui/headless/selection-tool-resolver.ts +11 -1
  111. package/src/ui-tailwind/chrome/chrome-preset-model.ts +13 -0
  112. package/src/ui-tailwind/chrome/tw-command-palette-mount.tsx +96 -0
  113. package/src/ui-tailwind/chrome/tw-context-menu.tsx +2 -1
  114. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +5 -4
  115. package/src/ui-tailwind/chrome/tw-mode-dock.tsx +6 -2
  116. package/src/ui-tailwind/chrome/use-container-breakpoint.ts +111 -0
  117. package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +0 -9
  118. package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +1 -0
  119. package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +6 -7
  120. package/src/ui-tailwind/editor-surface/pm-schema.ts +87 -25
  121. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +9 -0
  122. package/src/ui-tailwind/editor-surface/shape-renderer.ts +76 -14
  123. package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +18 -1
  124. package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +2 -0
  125. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +18 -2
  126. package/src/ui-tailwind/index.ts +9 -0
  127. package/src/ui-tailwind/page-chrome-model.ts +77 -5
  128. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +56 -1
  129. package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +2 -0
  130. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +116 -113
  131. package/src/ui-tailwind/review/tw-review-rail-footer.tsx +2 -2
  132. package/src/ui-tailwind/theme/tokens.ts +14 -0
  133. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +5 -0
  134. package/src/ui-tailwind/tw-review-workspace.tsx +29 -87
  135. package/src/validation/diagnostics.ts +1 -0
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from "react";
1
2
  import type { PersistedEditorSnapshot as RuntimePersistedEditorSnapshot } from "../core/state/editor-state.ts";
2
3
  import type { HarnessDebugPorts } from "../internal/harness-debug-ports.ts";
3
4
  import type { BlockNode, CanonicalParagraphFormatting, CanonicalRunFormatting, TextMark } from "../model/canonical-document.ts";
@@ -490,6 +491,39 @@ export interface SearchOptions {
490
491
  inStory?: EditorStoryTarget;
491
492
  }
492
493
 
494
+ /**
495
+ * §C4 — Post-match formatting filter for `findTextWithStyle`.
496
+ */
497
+ export interface TextStyleFilter {
498
+ /** Match only inside heading paragraphs (outlineLevel set or styleId matches /^Heading\d/i). */
499
+ inHeading?: boolean;
500
+ /** Run-level marks that ALL segments in the match must carry (AND per property, AND across segments). */
501
+ hasFormatting?: {
502
+ bold?: boolean;
503
+ italic?: boolean;
504
+ underline?: boolean;
505
+ strikethrough?: boolean;
506
+ };
507
+ /** Run-level marks where ALL segments must have AT LEAST ONE (OR per property, AND across segments). */
508
+ anyFormatting?: {
509
+ bold?: boolean;
510
+ italic?: boolean;
511
+ underline?: boolean;
512
+ strikethrough?: boolean;
513
+ };
514
+ }
515
+
516
+ /** Phase C §C5 — options for programmatic selection changes. */
517
+ export interface SetSelectionOptions {
518
+ /**
519
+ * When `true`, the selection change is applied locally but suppresses
520
+ * the next awareness cursor publish. Useful for agent-driven
521
+ * programmatic navigation that should not broadcast a cursor flicker
522
+ * to collaborators.
523
+ */
524
+ silent?: boolean;
525
+ }
526
+
493
527
  export interface SearchResultSnapshot {
494
528
  resultId: string;
495
529
  anchor: EditorAnchorProjection;
@@ -832,6 +866,8 @@ export interface SurfaceDrawingAnchor {
832
866
  simplePos?: boolean;
833
867
  /** docPr.id / .name / .descr — used for accessibility chrome and selection labels. */
834
868
  docPr?: { id: string; name?: string; descr?: string };
869
+ /** Polygon coords (21600ths-of-image units) for tight/through wrap clipping. Lane 6d N9.b. */
870
+ wrapPolygon?: Array<{ x: number; y: number }>;
835
871
  }
836
872
 
837
873
  /**
@@ -1055,6 +1091,8 @@ export interface ResolvedNumberingSnapshot {
1055
1091
  geometry: ResolvedNumberingGeometrySnapshot;
1056
1092
  /** CASCADED marker run formatting: docDefaults → paragraph style chain rPr → paragraph-mark rPr → level rPr. Added in Task 11. The raw level rPr is still available at geometry.markerRunProperties. */
1057
1093
  markerRunProperties?: CanonicalRunFormatting;
1094
+ /** Media-catalog ID for picture-bullet images (CO3.9). Set when the numbering level has `picBulletId` that resolves to a NumPicBullet entry. */
1095
+ picBulletMediaId?: string;
1058
1096
  }
1059
1097
 
1060
1098
  export type SurfaceBlockSnapshot =
@@ -1077,7 +1115,14 @@ export type SurfaceBlockSnapshot =
1077
1115
  spacing?: { before?: number; after?: number; line?: number; lineRule?: string };
1078
1116
  contextualSpacing?: boolean;
1079
1117
  indentation?: { left?: number; right?: number; firstLine?: number; hanging?: number };
1080
- borders?: { top?: unknown; left?: unknown; bottom?: unknown; right?: unknown; bar?: unknown; between?: unknown };
1118
+ borders?: {
1119
+ top?: PublicBorderSpec | null;
1120
+ left?: PublicBorderSpec | null;
1121
+ bottom?: PublicBorderSpec | null;
1122
+ right?: PublicBorderSpec | null;
1123
+ bar?: PublicBorderSpec | null;
1124
+ between?: PublicBorderSpec | null;
1125
+ };
1081
1126
  shading?: { fill?: string; color?: string; val?: string };
1082
1127
  tabStops?: Array<{ pos: number; val?: string; leader?: string }>;
1083
1128
  keepNext?: boolean;
@@ -1096,6 +1141,14 @@ export type SurfaceBlockSnapshot =
1096
1141
  to: number;
1097
1142
  styleId?: string;
1098
1143
  gridColumns: number[];
1144
+ /**
1145
+ * SOW gap G1 — when `tableResolved.widthType === "pct"`, a parallel array
1146
+ * of relative column widths (percent 0–100) derived from `gridColumns`
1147
+ * twips. The node-view prefers these for the `<colgroup>` so the column
1148
+ * proportions track the table's percent width instead of the absolute
1149
+ * `pt` values drifting against a `width: 100%` container.
1150
+ */
1151
+ gridColumnsRelative?: number[] | null;
1099
1152
  alignment?: "left" | "center" | "right";
1100
1153
  tblLook?: {
1101
1154
  /** R2d: raw `w:tblLook/@w:val` hex so vendor-extended bits survive round-trip. */
@@ -1204,9 +1257,11 @@ export type EditorWarningCode =
1204
1257
  | "export_roundtrip_risk"
1205
1258
  | "comment_anchor_detached"
1206
1259
  | "revision_anchor_detached"
1260
+ | "workflow_scope_invalidated"
1207
1261
  | "large_document_degraded"
1208
1262
  | "font_substitution"
1209
- | "image_missing";
1263
+ | "image_missing"
1264
+ | "review_target_not_found";
1210
1265
 
1211
1266
  export interface EditorWarning {
1212
1267
  warningId: string;
@@ -1223,6 +1278,13 @@ export interface EditorWarning {
1223
1278
  affectedAnchor?: EditorAnchorProjection;
1224
1279
  featureEntryId?: string;
1225
1280
  details?: Record<string, unknown>;
1281
+ /**
1282
+ * v2.0.0 — dual-error composite carrying a machine-facing `technical`
1283
+ * payload and an LLM-facing `llmMetadata` payload. Populated by the
1284
+ * editor on every warning emitted from v2.0.0 onward; older snapshots
1285
+ * may omit it. See {@link EditorDiagnostic}.
1286
+ */
1287
+ diagnostic?: EditorDiagnostic;
1226
1288
  }
1227
1289
 
1228
1290
  export type EditorErrorCode =
@@ -1240,6 +1302,150 @@ export interface EditorError {
1240
1302
  isFatal: boolean;
1241
1303
  source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
1242
1304
  details?: Record<string, unknown>;
1305
+ /**
1306
+ * v2.0.0 — dual-error composite. See {@link EditorDiagnostic}. Populated
1307
+ * by the editor from v2.0.0 onward; older snapshots may omit it.
1308
+ */
1309
+ diagnostic?: EditorDiagnostic;
1310
+ }
1311
+
1312
+ // ---------------------------------------------------------------------------
1313
+ // v2.0.0 — dual-error diagnostic composite
1314
+ // ---------------------------------------------------------------------------
1315
+
1316
+ /**
1317
+ * Unified source origin for any diagnostic emitted by the editor.
1318
+ * Superset of {@link EditorWarning.source} and {@link EditorError.source}
1319
+ * to cover API-surface + host-adapter rejections uniformly.
1320
+ */
1321
+ export type EditorDiagnosticSource =
1322
+ | "import"
1323
+ | "export"
1324
+ | "runtime"
1325
+ | "review"
1326
+ | "preservation"
1327
+ | "validation"
1328
+ | "datastore"
1329
+ | "host"
1330
+ | "api";
1331
+
1332
+ /**
1333
+ * Canonical machine-scannable code for every diagnostic surface in the
1334
+ * public API. Prefixed by convention (`import.*`, `export.*`, `runtime.*`,
1335
+ * `host.*`, `api.*`, `review.*`, `preservation.*`, `validation.*`).
1336
+ *
1337
+ * Legacy codes from {@link EditorWarningCode} / {@link EditorErrorCode} are
1338
+ * bridged into this union via the metadata table in
1339
+ * `src/runtime/diagnostics/code-metadata-table.ts`.
1340
+ *
1341
+ * Stability: `advanced-supported`. New codes are additive; existing codes
1342
+ * are permanent. Removal requires a major version bump.
1343
+ */
1344
+ export type EditorDiagnosticCode =
1345
+ | "import.failed"
1346
+ | "import.package_corrupt"
1347
+ | "import.normalized"
1348
+ | "import.unsupported_ooxml_preserved"
1349
+ | "import.unsupported_ooxml_locked"
1350
+ | "export.failed"
1351
+ | "export.roundtrip_risk"
1352
+ | "review.comment_anchor_detached"
1353
+ | "review.revision_anchor_detached"
1354
+ | "runtime.workflow_scope_invalidated"
1355
+ | "runtime.large_document_degraded"
1356
+ | "runtime.font_substitution"
1357
+ | "runtime.image_missing"
1358
+ | "runtime.internal_invariant"
1359
+ | "host.adapter_rejected"
1360
+ | "host.load_rejected"
1361
+ | "host.save_rejected"
1362
+ | "host.chart_preview_rejected"
1363
+ | "datastore.failed"
1364
+ | "datastore.load_rejected"
1365
+ | "datastore.save_rejected"
1366
+ | "validation.failed"
1367
+ | "validation.invariant_violated"
1368
+ | "api.invalid_regex"
1369
+ | "api.invalid_anchor"
1370
+ | "api.invalid_argument"
1371
+ | "api.metadata_resolver_missing"
1372
+ | "api.metadata_resolver_rejected"
1373
+ | "api.scope_not_found"
1374
+ | "api.collab_role_restricted"
1375
+ | "api.workflow_comment_only"
1376
+ | "api.command_blocked"
1377
+ // Lane 8 Track H (v2.x) — agent-helper widening. Metadata registered in
1378
+ // Phase 1; emission sites land with the Phase 2 runtime wiring.
1379
+ | "api.projection_unavailable"
1380
+ | "api.batch_edit_collision"
1381
+ | "api.workflow_patch_invalid"
1382
+ | "api.change_id_unknown"
1383
+ | "api.ai_explanation_anchor_invalid";
1384
+
1385
+ /**
1386
+ * The recovery class an agent / LLM uses to decide whether to retry,
1387
+ * reprompt, fall back, or surface to a human. Stable + enumerated.
1388
+ */
1389
+ export type EditorDiagnosticRecoveryClass =
1390
+ | "retry-safe"
1391
+ | "retry-with-backoff"
1392
+ | "requires-input"
1393
+ | "requires-resolver"
1394
+ | "requires-permission"
1395
+ | "requires-human"
1396
+ | "unrecoverable";
1397
+
1398
+ /**
1399
+ * Structured remediation the LLM can act on.
1400
+ */
1401
+ export type EditorDiagnosticRemediation =
1402
+ | { kind: "none" }
1403
+ | { kind: "retry"; afterMs?: number; maxAttempts?: number }
1404
+ | { kind: "fallback"; suggestion: string; payload?: Record<string, unknown> }
1405
+ | {
1406
+ kind: "escalate";
1407
+ to: "host" | "author" | "reviewer" | "admin";
1408
+ reason: string;
1409
+ };
1410
+
1411
+ /** Developer / machine-facing payload. */
1412
+ export interface EditorDiagnosticTechnical {
1413
+ message: string;
1414
+ source: EditorDiagnosticSource;
1415
+ stack?: string;
1416
+ cause?: {
1417
+ message: string;
1418
+ name?: string;
1419
+ stack?: string;
1420
+ };
1421
+ details?: Record<string, unknown>;
1422
+ affectedAnchor?: EditorAnchorProjection;
1423
+ featureEntryId?: string;
1424
+ }
1425
+
1426
+ /** LLM / agent-facing payload. */
1427
+ export interface EditorDiagnosticLlmMetadata {
1428
+ userSummary: string;
1429
+ remediation: EditorDiagnosticRemediation;
1430
+ recoveryClass: EditorDiagnosticRecoveryClass;
1431
+ echoedInput?: Record<string, unknown>;
1432
+ docsUrl?: string;
1433
+ tags?: string[];
1434
+ }
1435
+
1436
+ /**
1437
+ * v2.0.0 dual-error composite. LLM consumers read `llmMetadata` only;
1438
+ * developer consumers read `technical`. Host UI renders
1439
+ * `llmMetadata.userSummary` to end users. See
1440
+ * `docs/wiki/error-catalog.md` for the full code catalog.
1441
+ */
1442
+ export interface EditorDiagnostic {
1443
+ diagnosticId: string;
1444
+ severity: "fatal" | "error" | "warning" | "info";
1445
+ code: EditorDiagnosticCode;
1446
+ technical: EditorDiagnosticTechnical;
1447
+ llmMetadata: EditorDiagnosticLlmMetadata;
1448
+ emittedAt: string;
1243
1449
  }
1244
1450
 
1245
1451
  export type CompatibilityFeatureClass =
@@ -1924,6 +2130,27 @@ export interface AddScopeResult {
1924
2130
  export interface ExportDocxOptions {
1925
2131
  fileName?: string;
1926
2132
  reason?: string;
2133
+ /**
2134
+ * @experimental Lane 7c Slice 7c.4 (v2.0.0) — opt-in for Strict-flavor
2135
+ * OOXML export (ECMA-376 / ISO 29500-1 Strict, namespaces under
2136
+ * `http://purl.oclc.org/ooxml/...`). Transitional remains the default.
2137
+ *
2138
+ * **Status:** wired — `true` switches `serializeMainDocument` to the
2139
+ * Strict namespace URI set (`w`, `r`, `a`, `pic`, `wp`, `mc`) and
2140
+ * omits Microsoft extension namespace declarations
2141
+ * (`w14`/`w15`/`w16*`/`wp14`/`wps`) from the root element. `false`
2142
+ * or omitted preserves Transitional output byte-equivalent to
2143
+ * pre-7c.4 behavior.
2144
+ *
2145
+ * **Known scope limitations:** relationship `Type` URIs and
2146
+ * Content-Type URIs still use the Transitional form; extension
2147
+ * content wrapping via `mc:AlternateContent` / `mc:Fallback` is
2148
+ * not yet emitted. Full ISO 29500 Strict compliance requires those
2149
+ * follow-ups before this option graduates from `@experimental`.
2150
+ * See `docs/wiki/compatibility-and-validation.md` § Strict-flavor
2151
+ * export for the current capability matrix.
2152
+ */
2153
+ exportStrictOoxml?: boolean;
1927
2154
  }
1928
2155
 
1929
2156
  export interface ExportDelivery {
@@ -1940,6 +2167,35 @@ export interface ExportResult {
1940
2167
 
1941
2168
  export type WorkflowScopeMode = "edit" | "suggest" | "comment" | "view";
1942
2169
 
2170
+ /**
2171
+ * §C7 — Local chrome visibility mode. Never collab-replicated.
2172
+ * - `"all"`: show all scope rail entries + decorations (default).
2173
+ * - `"none"`: suppress all scope chrome; data layer unaffected.
2174
+ * - `"filtered"`: show only scopes matching `filter`.
2175
+ */
2176
+ export type ScopeChromeVisibility = "all" | "none" | "filtered";
2177
+
2178
+ /**
2179
+ * §C7 — Full chrome visibility state including an optional filter (only
2180
+ * relevant when `mode === "filtered"`).
2181
+ */
2182
+ export interface ScopeChromeVisibilityState {
2183
+ mode: ScopeChromeVisibility;
2184
+ filter?: ScopeQueryFilter;
2185
+ }
2186
+
2187
+ /**
2188
+ * §C8 — Per-scope chrome visibility. Default when absent is `"visible"`.
2189
+ * Collab-replicated: all peers see the same value. Distinct from
2190
+ * `setScopeChromeVisibility` (§C7), which is local view-state.
2191
+ *
2192
+ * - `"visible"`: rail entry + card + inline decoration (current behavior).
2193
+ * - `"hidden"`: in the rail but muted; card opens on explicit click; no decoration.
2194
+ * - `"invisible"`: never rendered; only queryable via API. Does NOT contribute
2195
+ * to InteractionGuard unless `mode === "view"` (explicit host opt-in).
2196
+ */
2197
+ export type ScopeVisibility = "visible" | "hidden" | "invisible";
2198
+
1943
2199
  export interface WorkflowCandidateRange {
1944
2200
  candidateId: string;
1945
2201
  storyTarget?: EditorStoryTarget;
@@ -1965,6 +2221,12 @@ export interface WorkflowScope {
1965
2221
  * `"inherit"`.
1966
2222
  */
1967
2223
  metadataPersistence?: ScopeMetadataPersistence;
2224
+ /**
2225
+ * §C8 — Per-scope chrome visibility. Absent / `undefined` is equivalent to
2226
+ * `"visible"`. Collab-replicated via the existing `workflow.set-overlay`
2227
+ * broadcast; old peers ignore the unknown field (read as `undefined` = visible).
2228
+ */
2229
+ visibility?: ScopeVisibility;
1968
2230
  }
1969
2231
 
1970
2232
  export interface WorkflowScopeMetadataField {
@@ -2239,6 +2501,8 @@ export interface ScopeCardModel {
2239
2501
  posture: ScopeRailPosture;
2240
2502
  label: string;
2241
2503
  primaryAnchorRect: RenderFrameRect | null;
2504
+ /** K2 — source anchor for the scope; passed to `onScopeAskAgent` so hosts skip a `getScope()` round-trip. */
2505
+ anchor?: EditorAnchorProjection;
2242
2506
  issue?: IssueMetadataValue;
2243
2507
  /** Id-only lookup; `suggestionGroups` holds the full entries. */
2244
2508
  suggestionGroupIds: readonly string[];
@@ -2303,6 +2567,13 @@ export interface InteractionGuardSnapshot {
2303
2567
  effectiveMode: EffectiveSelectionMode;
2304
2568
  matchedScopeId?: string;
2305
2569
  matchedScopeMode?: WorkflowScopeMode;
2570
+ /** §C6 — all scopes covering the selection, ordered outermost→innermost
2571
+ * (widest span first). Most-restrictive mode wins for effectiveMode. */
2572
+ matchedScopeStack?: Array<{
2573
+ scopeId: string;
2574
+ mode: WorkflowScopeMode;
2575
+ visibility: ScopeVisibility;
2576
+ }>;
2306
2577
  targetAccess?: "direct-edit" | "suggest" | "comment-only" | "view-only" | "blocked";
2307
2578
  commandCapabilities?: Array<{
2308
2579
  family: "text" | "formatting" | "structure";
@@ -2646,8 +2917,25 @@ export type AutosaveState =
2646
2917
  | { status: "saved"; savedAt: string }
2647
2918
  | { status: "error"; error: EditorError };
2648
2919
 
2920
+ /**
2921
+ * Controls the editor's automatic session-state persistence behaviour.
2922
+ * Passed as `autosave` on `WordReviewEditorProps`.
2923
+ *
2924
+ * When omitted entirely, autosave is **enabled** with a 2 000 ms debounce.
2925
+ */
2649
2926
  export interface AutosaveConfig {
2927
+ /**
2928
+ * Set to `false` to disable autosave entirely.
2929
+ * @default true
2930
+ */
2650
2931
  enabled?: boolean;
2932
+ /**
2933
+ * Milliseconds of idle time after the last edit before
2934
+ * `hostAdapter.saveSession` is called. Minimum effective value is
2935
+ * 500 ms (values below are clamped). Has no effect when `enabled` is
2936
+ * `false`.
2937
+ * @default 2000
2938
+ */
2651
2939
  debounceMs?: number;
2652
2940
  }
2653
2941
 
@@ -2710,8 +2998,8 @@ export type WordReviewEditorEvent =
2710
2998
  * the previous and current runtime render snapshot. Includes
2711
2999
  * additions, deletions, body edits, reply appends, and
2712
3000
  * resolution-state transitions. Consumers can call
2713
- * `editorRef.current.getComments()` to obtain the full updated
2714
- * `CommentSidebarSnapshot`.
3001
+ * `editorRef.current.getCommentSidebarSnapshot()` to obtain the full
3002
+ * updated `CommentSidebarSnapshot`.
2715
3003
  *
2716
3004
  * The array is always non-empty when this event fires. When the
2717
3005
  * snapshot's `comments` reference is unchanged between commits,
@@ -2835,6 +3123,13 @@ export type WordReviewEditorEvent =
2835
3123
  documentId: string;
2836
3124
  command: string;
2837
3125
  reasons: WorkflowBlockedCommandReason[];
3126
+ /**
3127
+ * v2.0.0 — per-reason diagnostic composite. When present, carries
3128
+ * one {@link EditorDiagnostic} per entry in `reasons` (matching
3129
+ * indices). Older snapshots may omit this field; LLM consumers
3130
+ * should tolerate absence.
3131
+ */
3132
+ diagnostics?: EditorDiagnostic[];
2838
3133
  }
2839
3134
  | WordReviewEditorPasteEvent
2840
3135
  | {
@@ -3130,8 +3425,25 @@ export interface ChartPreviewResolveParams {
3130
3425
  }
3131
3426
 
3132
3427
  export interface EditorHostAdapter {
3428
+ /**
3429
+ * Called once at load time to retrieve a previously-saved session
3430
+ * blob. Rejections are treated as fatal load failures and surfaced
3431
+ * via the `onError` callback with `code: "host_load_failed"`. The
3432
+ * editor does not retry.
3433
+ */
3133
3434
  load?(params: LoadRequest): Promise<LoadResult>;
3435
+ /**
3436
+ * Called after each debounce window when the in-memory session state
3437
+ * has changed. Rejections are non-fatal: the editor emits
3438
+ * `autosave_state { status: "error" }` and retries on the next dirty
3439
+ * commit. Must be idempotent.
3440
+ */
3134
3441
  saveSession?(params: SaveSessionParams): Promise<SaveSessionResult>;
3442
+ /**
3443
+ * Called when the user triggers an explicit export. Rejections
3444
+ * propagate as a rejected `Promise<ExportResult>` from `exportDocx()`
3445
+ * — the host is responsible for surfacing the error to the user.
3446
+ */
3135
3447
  saveExport?(params: SaveExportParams): Promise<SaveExportResult>;
3136
3448
  logEvent?(event: EditorTelemetryEvent): void;
3137
3449
  /**
@@ -3146,6 +3458,10 @@ export interface EditorHostAdapter {
3146
3458
  * for a PNG magic number, `image/svg+xml` otherwise. Hosts that
3147
3459
  * need a different content type should extend this contract in a
3148
3460
  * follow-up.
3461
+ *
3462
+ * Rejections and thrown exceptions are caught by the editor and
3463
+ * treated identically to a `null` return — the badge fallback path
3464
+ * activates and the error is logged non-fatally.
3149
3465
  */
3150
3466
  renderChartPreview?(params: ChartPreviewResolveParams): Promise<Uint8Array | null>;
3151
3467
  }
@@ -3157,6 +3473,404 @@ export interface EditorDatastoreAdapter {
3157
3473
  logEvent?(event: EditorTelemetryEvent): void;
3158
3474
  }
3159
3475
 
3476
+ // ---------------------------------------------------------------------------
3477
+ // v2.x — Lane 8 Track H agent-helper widening (Phase 1: types only)
3478
+ //
3479
+ // Derived from the CLM workblock (`docs/CLM (10).yaml`) hand-rolled patterns:
3480
+ // `snapshot_to_projection`, back-to-front anchor-sorted field fill,
3481
+ // `change_id → range` walking, and read-merge-write workflow-overlay
3482
+ // annotation. See `docs/wiki/agent-helpers.md` for the narrative and
3483
+ // `docs/plans/lane-8-api-ergonomics.md` § Track H for the phased plan.
3484
+ //
3485
+ // Phase 1 ships type declarations and optional method signatures on
3486
+ // `WordReviewEditorRef`; runtime wiring lands in Phase 2, Python parity
3487
+ // in Phase 3.
3488
+ // ---------------------------------------------------------------------------
3489
+
3490
+ /**
3491
+ * Options controlling the shape of the annotated-text projection returned
3492
+ * by {@link WordReviewEditorRef.getRenderSnapshotAsText} /
3493
+ * {@link EditorSurfaceSnapshotLike.toAnnotatedText}.
3494
+ *
3495
+ * All flags default to `true`; callers who only want the raw text can
3496
+ * opt everything off to skip the post-processing cost.
3497
+ */
3498
+ export interface TextProjectionOptions {
3499
+ /**
3500
+ * When `true` (default), every line in {@link TextProjection.lines}
3501
+ * carries the `[start, end)` runtime offsets the line spans in the
3502
+ * active story. Offsets are the same unit `findAllText` / `replaceText`
3503
+ * / `addScope` accept, so agent code can feed offsets back into
3504
+ * mutation calls without re-projection.
3505
+ */
3506
+ withOffsets?: boolean;
3507
+ /**
3508
+ * When `true` (default), {@link TextProjection.lines} is populated.
3509
+ * When `false`, only {@link TextProjection.text} is computed; useful
3510
+ * for regex search where line boundaries don't matter.
3511
+ */
3512
+ withLineMap?: boolean;
3513
+ /**
3514
+ * When `true` (default), {@link TextProjection.stories} is populated
3515
+ * with one entry per non-main story (header/footer/footnote/endnote)
3516
+ * that carries its own offset space. Set `false` to skip secondary
3517
+ * stories entirely — main body only.
3518
+ */
3519
+ withStoryMap?: boolean;
3520
+ /**
3521
+ * Restrict projection to a specific story. Defaults to main body.
3522
+ * Unknown story targets return an empty projection (no throw).
3523
+ */
3524
+ storyTarget?: EditorStoryTarget;
3525
+ }
3526
+
3527
+ /**
3528
+ * A single line within an annotated text projection. Lines are produced
3529
+ * by the same line-segmentation logic that backs `findAllText`'s
3530
+ * `matchLocation.lineIndex`, so agents can round-trip between
3531
+ * `findAllText` results and line indices deterministically.
3532
+ */
3533
+ export interface TextProjectionLine {
3534
+ /** Zero-based line index within the containing story. */
3535
+ lineIndex: number;
3536
+ /** Line text, without trailing newline. */
3537
+ text: string;
3538
+ /**
3539
+ * `[start, end)` runtime offsets this line spans. End is exclusive
3540
+ * of any trailing newline. Present only when
3541
+ * {@link TextProjectionOptions.withOffsets} is `true`.
3542
+ */
3543
+ start?: number;
3544
+ end?: number;
3545
+ /** Block id the line belongs to, when derivable. */
3546
+ blockId?: string;
3547
+ /** Story the line belongs to; defaults to main body. */
3548
+ storyTarget?: EditorStoryTarget;
3549
+ }
3550
+
3551
+ /**
3552
+ * Per-story section of a text projection. Main body is returned on the
3553
+ * top-level {@link TextProjection} fields; non-main stories each get one
3554
+ * entry here with their own offset space.
3555
+ */
3556
+ export interface TextProjectionStoryEntry {
3557
+ storyTarget: EditorStoryTarget;
3558
+ text: string;
3559
+ lines?: TextProjectionLine[];
3560
+ }
3561
+
3562
+ /**
3563
+ * Annotated linear-text projection of the render snapshot. Replaces the
3564
+ * hand-written `snapshot_to_projection` / `workblock.cdr` wrapper that
3565
+ * CLM workblocks carry today. Text is in the same offset space as
3566
+ * `findAllText`, `replaceText`, and `addScope` ranges, so agent code
3567
+ * can search the flattened text, then feed the matching offsets
3568
+ * directly back into mutation APIs.
3569
+ */
3570
+ export interface TextProjection {
3571
+ /** Main-body text, newline-separated. */
3572
+ text: string;
3573
+ /** Main-body line map (absent when `withLineMap: false`). */
3574
+ lines?: TextProjectionLine[];
3575
+ /** Non-main-body stories (absent when `withStoryMap: false`). */
3576
+ stories?: TextProjectionStoryEntry[];
3577
+ /**
3578
+ * Total line count across main + stories. Stable even when
3579
+ * `withLineMap: false` (counted without emitting the array).
3580
+ */
3581
+ totalLines: number;
3582
+ }
3583
+
3584
+ /**
3585
+ * Typed handle for a tracked change or comment thread as returned by
3586
+ * {@link WordReviewEditorRef.findChangeById} /
3587
+ * {@link WordReviewEditorRef.findAllChanges}. Collapses the current
3588
+ * two-step `getComments() → .threads` + `getTrackedChanges() → .revisions`
3589
+ * walk that CLM's `_get_range_from_diff_items` / `_get_range_from_doc`
3590
+ * open-codes today.
3591
+ */
3592
+ export interface ChangeAnchor {
3593
+ kind: "comment" | "revision";
3594
+ /** `commentId` (when `kind === "comment"`) or `revisionId`. */
3595
+ id: string;
3596
+ /**
3597
+ * Best-known live anchor. For comments: the thread anchor. For
3598
+ * revisions: `anchor.range` (fresh) or `anchor.lastKnownRange`
3599
+ * (detached). Consumers should treat detached anchors as advisory.
3600
+ */
3601
+ anchor: EditorAnchorProjection;
3602
+ storyTarget?: EditorStoryTarget;
3603
+ /** `false` when the underlying thread/revision is detached. */
3604
+ isLive: boolean;
3605
+ }
3606
+
3607
+ /**
3608
+ * Filter for {@link WordReviewEditorRef.findAllChanges}. AND-combined;
3609
+ * omitted fields do not constrain the result.
3610
+ */
3611
+ export interface ChangeFilter {
3612
+ kind?: "comment" | "revision";
3613
+ storyTarget?: EditorStoryTarget;
3614
+ authorId?: string;
3615
+ /** Only return changes authored at/after this revision token. */
3616
+ sinceRevisionToken?: string;
3617
+ /** Only return live (non-detached) changes. Defaults to `false`. */
3618
+ liveOnly?: boolean;
3619
+ }
3620
+
3621
+ /**
3622
+ * One edit in a {@link WordReviewEditorRef.applyBatchedEdits} batch.
3623
+ * Discriminated by `kind`. Each shape mirrors an existing ref method
3624
+ * (`replaceText`, `insertFragment`, `setFontFamily`-style mark ops).
3625
+ */
3626
+ export type BatchEditOperation =
3627
+ | {
3628
+ kind: "replace-text";
3629
+ target: EditorAnchorProjection;
3630
+ text: string;
3631
+ formatting?: TextFormattingDirective;
3632
+ }
3633
+ | {
3634
+ kind: "insert-fragment";
3635
+ target: EditorAnchorProjection;
3636
+ fragment: CanonicalDocumentFragment;
3637
+ }
3638
+ | {
3639
+ kind: "set-mark";
3640
+ target: EditorAnchorProjection;
3641
+ mark: TextMark;
3642
+ }
3643
+ | {
3644
+ kind: "clear-mark";
3645
+ target: EditorAnchorProjection;
3646
+ mark: TextMark["type"];
3647
+ };
3648
+
3649
+ /**
3650
+ * Sequencing contract for {@link WordReviewEditorRef.applyBatchedEdits}.
3651
+ *
3652
+ * - `"back-to-front"`: edits are sorted by descending `target.range.to`
3653
+ * before apply, so earlier offsets are not shifted by later edits.
3654
+ * Use for field-fill / find-and-replace workflows. Default.
3655
+ * - `"atomic"`: edits are applied in array order inside a single
3656
+ * `startAction("batch")` bracket; any failure rolls back the
3657
+ * whole batch via a single `undo()`.
3658
+ */
3659
+ export interface BatchEditOptions {
3660
+ mode?: "back-to-front" | "atomic";
3661
+ /** Optional label for the action bracket; surfaces in undo UX. */
3662
+ actionLabel?: string;
3663
+ }
3664
+
3665
+ export interface BatchEditEntryResult {
3666
+ ok: boolean;
3667
+ /** Diagnostic (recoverable skip) when `ok === false`. */
3668
+ diagnostic?: EditorDiagnostic;
3669
+ }
3670
+
3671
+ export interface BatchEditResult {
3672
+ appliedCount: number;
3673
+ skippedCount: number;
3674
+ entries: BatchEditEntryResult[];
3675
+ }
3676
+
3677
+ /**
3678
+ * Differential patch for {@link WorkflowOverlay}. Replaces the
3679
+ * read-merge-write pattern documented in `public-api.md` under
3680
+ * `getWorkflowOverlay()`. Runtime-authored fields (`scopes` from
3681
+ * `addScope`, `workItems`) are never clobbered; only the fields
3682
+ * named in the patch are touched.
3683
+ */
3684
+ export interface WorkflowOverlayPatch {
3685
+ addScopes?: WorkflowScope[];
3686
+ removeScopeIds?: string[];
3687
+ addCandidates?: WorkflowCandidateRange[];
3688
+ removeCandidateIds?: string[];
3689
+ /** Shallow-merge into existing work items by `workItemId`. */
3690
+ mergeWorkItems?: WorkflowWorkItem[];
3691
+ /**
3692
+ * When set, overlay-level `metadataPersistence` is replaced. Omit to
3693
+ * leave the current value alone.
3694
+ */
3695
+ metadataPersistence?: MetadataPersistenceMode;
3696
+ }
3697
+
3698
+ /**
3699
+ * Input shape for {@link WordReviewEditorRef.attachAiExplanationScope}.
3700
+ * Collapses the "find change → build scope → patch overlay" sequence
3701
+ * CLM workblocks hand-roll in `annotate_document_with_explanations`.
3702
+ */
3703
+ export interface AiExplanationScopeInput {
3704
+ /** `commentId` or `revisionId` to anchor the explanation against. */
3705
+ changeId: string;
3706
+ explanation: {
3707
+ summary: string;
3708
+ detail?: string;
3709
+ riskLevel?: "low" | "medium" | "high" | "unknown";
3710
+ recommendedAction?: "accept" | "reject" | "review" | "escalate";
3711
+ actionRationale?: string;
3712
+ /** Free-form location label (e.g., "§4.2 payment terms"). */
3713
+ location?: string;
3714
+ };
3715
+ /** Scope mode. Defaults to `"view"` — advisory-only. */
3716
+ mode?: WorkflowScopeMode;
3717
+ /** Optional caller-supplied scope id; runtime mints one when absent. */
3718
+ scopeId?: string;
3719
+ /** Domain tag. Defaults to `"ai-suggestion"`. */
3720
+ domain?: string;
3721
+ }
3722
+
3723
+ export interface AiExplanationScopeResult {
3724
+ scopeId: string;
3725
+ candidateId: string;
3726
+ anchor: EditorAnchorProjection;
3727
+ }
3728
+
3729
+ // ---------------------------------------------------------------------------
3730
+ // v2.0.0 — Track D purpose-grouped ref projections
3731
+ // ---------------------------------------------------------------------------
3732
+
3733
+ /**
3734
+ * Ergonomic projection of comment-related methods. Pure dispatch over
3735
+ * {@link WordReviewEditorRef} — flat methods keep working. LLM workblocks
3736
+ * and wrapper layers should prefer the projection to narrow the surface
3737
+ * they import.
3738
+ */
3739
+ export interface WordReviewEditorCommentsFacet {
3740
+ add(params: AddCommentParams): AddCommentResult;
3741
+ addReply(commentId: string, body: string): AddCommentReplyResult | null;
3742
+ resolve(commentId: string): void;
3743
+ reopen(commentId: string): void;
3744
+ edit(commentId: string, body: string): void;
3745
+ delete(commentId: string): void;
3746
+ open(commentId: string): void;
3747
+ scrollTo(commentId: string): void;
3748
+ get(): CommentSidebarSnapshot;
3749
+ /**
3750
+ * Track H (v2.x Phase 1 — types only; runtime wired in Phase 2). Typed
3751
+ * id lookup over `get().threads`. Returns `null` when the id is unknown.
3752
+ */
3753
+ getById?(commentId: string): CommentSidebarThreadSnapshot | null;
3754
+ }
3755
+
3756
+ /** Ergonomic projection of tracked-change methods. */
3757
+ export interface WordReviewEditorChangesFacet {
3758
+ accept(changeId: string): void;
3759
+ reject(changeId: string): void;
3760
+ acceptAll(): void;
3761
+ rejectAll(): void;
3762
+ acceptGroup(groupId: string): void;
3763
+ rejectGroup(groupId: string): void;
3764
+ scrollTo(revisionId: string): void;
3765
+ get(): TrackedChangesSnapshot;
3766
+ getSuggestions(): SuggestionsSnapshot;
3767
+ /**
3768
+ * Track H (v2.x Phase 1 — types only; runtime wired in Phase 2). Typed
3769
+ * id lookup over `get().revisions`. Returns `null` when unknown.
3770
+ */
3771
+ getById?(revisionId: string): TrackedChangeEntrySnapshot | null;
3772
+ /**
3773
+ * Track H — unified change-lookup across comments + revisions. Replaces
3774
+ * the hand-rolled `_get_range_from_diff_items` walk.
3775
+ */
3776
+ findById?(changeId: string): ChangeAnchor | null;
3777
+ /** Track H — filter over all comments + revisions. */
3778
+ findAll?(filter?: ChangeFilter): ChangeAnchor[];
3779
+ }
3780
+
3781
+ /** Ergonomic projection of field / TOC operations. */
3782
+ export interface WordReviewEditorFieldsFacet {
3783
+ getSnapshot(): FieldSnapshot;
3784
+ update(options?: UpdateFieldsOptions): UpdateFieldsResult;
3785
+ updateToc(options?: TocRefreshOptions): TocRefreshResult;
3786
+ }
3787
+
3788
+ /** Ergonomic projection of document-level operations. */
3789
+ export interface WordReviewEditorDocumentFacet {
3790
+ export(options?: ExportDocxOptions): Promise<ExportResult>;
3791
+ getSessionState(): EditorSessionState;
3792
+ getSnapshot(): PersistedEditorSnapshot;
3793
+ getRenderSnapshot(): RuntimeRenderSnapshot;
3794
+ isDirty(): boolean;
3795
+ getCompatibilityReport(): CompatibilityReport;
3796
+ getStats(): DocumentStats;
3797
+ /**
3798
+ * Track H (v2.x Phase 1 — types only; runtime wired in Phase 2).
3799
+ * Annotated linear-text projection with stable runtime offsets.
3800
+ * Replaces the hand-written `snapshot_to_projection` helper.
3801
+ */
3802
+ getAsText?(options?: TextProjectionOptions): TextProjection;
3803
+ /**
3804
+ * Track H — sequenced replace/insert/mark batch with offset-shift
3805
+ * protection. Collapses the back-to-front sort + bytes-chain pattern
3806
+ * from CLM's `generate_filled_document`.
3807
+ */
3808
+ applyBatchedEdits?(
3809
+ edits: BatchEditOperation[],
3810
+ options?: BatchEditOptions,
3811
+ ): Promise<BatchEditResult>;
3812
+ /**
3813
+ * Track H — one-shot `patchWorkflowOverlay` + `exportDocx`. Use for
3814
+ * AI-annotation pipelines that would otherwise run two stateless
3815
+ * round-trips through the same document.
3816
+ */
3817
+ exportWithOverlayPatch?(
3818
+ patch: WorkflowOverlayPatch,
3819
+ exportOptions?: ExportDocxOptions,
3820
+ ): Promise<ExportResult>;
3821
+ }
3822
+
3823
+ /**
3824
+ * Ergonomic projection of workflow-scope query methods. Phase C+ LLM
3825
+ * helpers (`adjust`, `resize`, `alignToBoundary`, `addForText`,
3826
+ * `applyPlaybook`, `getRenderProjection`) will be added additively as
3827
+ * the underlying ref methods merge from the Phase C+ lane.
3828
+ */
3829
+ export interface WordReviewEditorScopesFacet {
3830
+ add(params: AddScopeParams): AddScopeResult;
3831
+ get(scopeId: string): WorkflowScope | null;
3832
+ remove(scopeId: string): void;
3833
+ query(filter?: ScopeQueryFilter): ScopeQueryResult[];
3834
+ findAt(
3835
+ position: EditorAnchorProjection,
3836
+ options?: { includeHidden?: boolean; includeInvisible?: boolean },
3837
+ ): ScopeQueryResult[];
3838
+ findIntersecting(
3839
+ range: EditorAnchorProjection,
3840
+ options?: {
3841
+ includeHidden?: boolean;
3842
+ includeInvisible?: boolean;
3843
+ mode?: "overlap" | "contain";
3844
+ },
3845
+ ): ScopeQueryResult[];
3846
+ /**
3847
+ * Track H (v2.x Phase 1 — types only; runtime wired in Phase 2).
3848
+ * Differential overlay patch. Never clobbers engine-authored scopes
3849
+ * or work items — only the fields named in the patch are touched.
3850
+ */
3851
+ patch?(patch: WorkflowOverlayPatch): void;
3852
+ /**
3853
+ * Track H — one-shot convenience: resolve `changeId` via
3854
+ * `findChangeById`, build an AI-explanation scope + candidate, and
3855
+ * patch the overlay. Collapses ~60 lines of CLM workblock glue.
3856
+ */
3857
+ attachAiExplanation?(input: AiExplanationScopeInput): AiExplanationScopeResult;
3858
+ }
3859
+
3860
+ /**
3861
+ * Ergonomic projection of diagnostic surfaces. Exposes the legacy warning
3862
+ * array plus the v2.0.0 code catalog for LLM consumers that want to
3863
+ * discover remediation strategies up front (before an error fires).
3864
+ */
3865
+ export interface WordReviewEditorDiagnosticsFacet {
3866
+ getWarnings(): EditorWarning[];
3867
+ getCatalog(): ReadonlyArray<{
3868
+ code: EditorDiagnosticCode;
3869
+ severity: "fatal" | "error" | "warning" | "info";
3870
+ llmMetadata: EditorDiagnosticLlmMetadata;
3871
+ }>;
3872
+ }
3873
+
3160
3874
  export interface WordReviewEditorRef {
3161
3875
  focus(): void;
3162
3876
  blur(): void;
@@ -3166,7 +3880,17 @@ export interface WordReviewEditorRef {
3166
3880
  openComment(commentId: string): void;
3167
3881
  resolveComment(commentId: string): void;
3168
3882
  reopenComment(commentId: string): void;
3169
- addCommentReply(commentId: string, body: string): AddCommentReplyResult;
3883
+ /**
3884
+ * Append a reply entry to an existing thread. Returns `{ commentId,
3885
+ * entryId }` on success and `null` when the thread is unknown, resolved,
3886
+ * or detached — in that case a `review_target_not_found` warning fires
3887
+ * on `onWarning` / `warning_added` with `details.op = "addCommentReply"`
3888
+ * and `details.reason` ∈ `{ "comment_unknown", "comment_status" }`.
3889
+ */
3890
+ addCommentReply(
3891
+ commentId: string,
3892
+ body: string,
3893
+ ): AddCommentReplyResult | null;
3170
3894
  editCommentBody(commentId: string, body: string): void;
3171
3895
  deleteComment(commentId: string): void;
3172
3896
  /**
@@ -3187,6 +3911,34 @@ export interface WordReviewEditorRef {
3187
3911
  * metadata record. No-op when the scopeId is unknown.
3188
3912
  */
3189
3913
  removeScope(scopeId: string): void;
3914
+ /**
3915
+ * §C8 — Convenience: adds a scope with `visibility: "invisible"` atomically.
3916
+ * Mode defaults to `"comment"` — invisible scopes carry no InteractionGuard
3917
+ * constraint unless `mode: "view"` is passed explicitly.
3918
+ */
3919
+ addInvisibleScope(
3920
+ params: Omit<AddScopeParams, "mode"> & { mode?: WorkflowScopeMode },
3921
+ ): AddScopeResult;
3922
+ /**
3923
+ * §C8 — Set a scope's visibility. Collab-replicated; all peers see the same
3924
+ * chrome state after the next overlay-replay cycle.
3925
+ */
3926
+ setScopeVisibility(scopeId: string, visibility: ScopeVisibility): void;
3927
+ /**
3928
+ * §C8 — Get a scope's current visibility. Returns `"visible"` for unknown
3929
+ * scopes or when the `visibility` field has never been set.
3930
+ */
3931
+ getScopeVisibility(scopeId: string): ScopeVisibility;
3932
+ /**
3933
+ * §C7 — Set the local chrome-visibility state. Local view-state only —
3934
+ * never collab-replicated. Controls whether the scope rail / decorations
3935
+ * render in the current session.
3936
+ */
3937
+ setScopeChromeVisibility(state: ScopeChromeVisibilityState): void;
3938
+ /**
3939
+ * §C7 — Get the local chrome-visibility state. Default is `{ mode: "all" }`.
3940
+ */
3941
+ getScopeChromeVisibility(): ScopeChromeVisibilityState;
3190
3942
  acceptChange(changeId: string): void;
3191
3943
  rejectChange(changeId: string): void;
3192
3944
  acceptAllChanges(): void;
@@ -3219,7 +3971,9 @@ export interface WordReviewEditorRef {
3219
3971
  getCommentSidebarSnapshot(): CommentSidebarSnapshot;
3220
3972
  getTrackedChangesSnapshot(): TrackedChangesSnapshot;
3221
3973
  getSuggestionsSnapshot(): SuggestionsSnapshot;
3974
+ /** @deprecated Use {@link getCommentSidebarSnapshot} instead. */
3222
3975
  getComments(): CommentSidebarSnapshot;
3976
+ /** @deprecated Use {@link getTrackedChangesSnapshot} instead. */
3223
3977
  getTrackedChanges(): TrackedChangesSnapshot;
3224
3978
  isDirty(): boolean;
3225
3979
  getFormattingState(): FormattingStateSnapshot;
@@ -3326,7 +4080,7 @@ export interface WordReviewEditorRef {
3326
4080
  setCellBackground(color: string): void;
3327
4081
  search(query: string, options?: SearchOptions): SearchResultSnapshot[];
3328
4082
  clearSearch(): void;
3329
- setSelection(selection: SelectionSnapshot | null): void;
4083
+ setSelection(selection: SelectionSnapshot | null, options?: SetSelectionOptions): void;
3330
4084
  scrollToRevision(revisionId: string): void;
3331
4085
  scrollToComment(commentId: string): void;
3332
4086
  openStory(target: EditorStoryTarget): void;
@@ -3414,6 +4168,18 @@ export interface WordReviewEditorRef {
3414
4168
  * Returns `[]` when no workflow overlay has been set.
3415
4169
  */
3416
4170
  queryScopes(filter?: ScopeQueryFilter): ScopeQueryResult[];
4171
+ /**
4172
+ * Phase C §C1 — live subscription to `queryScopes(filter)` results.
4173
+ * Fires the callback immediately, then once per settled commit after any
4174
+ * overlay change that passes the filter. Multiple changes in one
4175
+ * synchronous burst are coalesced into a single callback via `setTimeout(0)`.
4176
+ * Shallow-equality dedup: callback skips if results are unchanged.
4177
+ * Returns an unsubscribe function.
4178
+ */
4179
+ subscribeToScopeQuery(
4180
+ filter: ScopeQueryFilter,
4181
+ callback: (results: ScopeQueryResult[]) => void,
4182
+ ): () => void;
3417
4183
  /**
3418
4184
  * Phase C §C2 — every scope whose marker range contains `position.from`
3419
4185
  * (end-inclusive), ordered outermost → innermost. Pass a zero-length
@@ -3470,7 +4236,7 @@ export interface WordReviewEditorRef {
3470
4236
  */
3471
4237
  selectFirstText(
3472
4238
  query: string,
3473
- options?: SearchOptions,
4239
+ options?: SearchOptions & SetSelectionOptions,
3474
4240
  ): boolean;
3475
4241
  /**
3476
4242
  * Phase C §C3 — select first text match and return the total match count.
@@ -3479,7 +4245,33 @@ export interface WordReviewEditorRef {
3479
4245
  */
3480
4246
  selectAllText(
3481
4247
  query: string,
4248
+ options?: SearchOptions & SetSelectionOptions,
4249
+ ): number;
4250
+ /**
4251
+ * Phase C §C4 — find all text matches that also satisfy the given style
4252
+ * filter. Combines `findAllText` text search with paragraph-level and
4253
+ * run-level formatting predicates:
4254
+ * - `inHeading`: paragraph must be a heading (outlineLevel set or styleId
4255
+ * matches /^Heading\d/i).
4256
+ * - `hasFormatting`: ALL segments in the match must carry ALL specified
4257
+ * formatting marks (AND semantics per property, AND across segments).
4258
+ * - `anyFormatting`: ALL segments in the match must carry AT LEAST ONE of
4259
+ * the specified marks (OR semantics per property, AND across segments).
4260
+ * An empty filter is a no-op — returns all text matches.
4261
+ */
4262
+ findTextWithStyle(
4263
+ query: string,
4264
+ filter: TextStyleFilter,
3482
4265
  options?: SearchOptions,
4266
+ ): EditorAnchorProjection[];
4267
+ /**
4268
+ * Phase C §C4 — convenience wrapper: `findTextWithStyle` + select the first
4269
+ * result. Returns the total match count (0 when no matches).
4270
+ */
4271
+ selectTextWithStyle(
4272
+ query: string,
4273
+ filter: TextStyleFilter,
4274
+ options?: SearchOptions & SetSelectionOptions,
3483
4275
  ): number;
3484
4276
  /**
3485
4277
  * Schema 1.1 — set the overlay default for metadata persistence.
@@ -3525,7 +4317,9 @@ export interface WordReviewEditorRef {
3525
4317
  * `"external"`, call `resolver.resolve(ref)`, inline the returned
3526
4318
  * value, clear `storageRef`, preserve `metadataVersion` as a hint.
3527
4319
  * Call this before exporting a docx outside the resolver's reach
3528
- * (e.g., sending to an external supplier).
4320
+ * (e.g., sending to an external supplier). Rejects if
4321
+ * `resolver.resolve` throws for any entry; partial conversions are
4322
+ * rolled back.
3529
4323
  */
3530
4324
  convertScopesToInternal(scopeIds: string[]): Promise<void>;
3531
4325
  /**
@@ -3564,6 +4358,8 @@ export interface WordReviewEditorRef {
3564
4358
  /**
3565
4359
  * Re-attempt any persists that failed since the last successful
3566
4360
  * write. Pass a namespace to scope the retry; omit to retry all.
4361
+ * Rejects if the persister throws on retry; the failed namespace
4362
+ * remains in the pending queue.
3567
4363
  */
3568
4364
  retryPendingPersist(namespace?: EditorStateNamespace): Promise<void>;
3569
4365
  setHostAnnotationOverlay(overlay: HostAnnotationOverlay): void;
@@ -3580,6 +4376,92 @@ export interface WordReviewEditorRef {
3580
4376
  query?: RuntimeContextAnalyticsQuery,
3581
4377
  ): RuntimeContextAnalyticsSnapshot | null;
3582
4378
 
4379
+ // -------------------------------------------------------------------------
4380
+ // Track H — agent-helper widening (v2.x Phase 1: optional; wired Phase 2)
4381
+ // -------------------------------------------------------------------------
4382
+
4383
+ /**
4384
+ * Track H T1 — annotated linear-text projection with stable runtime
4385
+ * offsets. Replaces the hand-written `snapshot_to_projection` helper
4386
+ * that CLM workblocks carry in `workblock.cdr`.
4387
+ *
4388
+ * **Status:** @experimental (v2.x). Types land in Phase 1; runtime
4389
+ * wiring in Phase 2.
4390
+ */
4391
+ getRenderSnapshotAsText?(options?: TextProjectionOptions): TextProjection;
4392
+ /**
4393
+ * Track H T2 — typed lookup by `commentId` or `revisionId` across
4394
+ * comments + tracked changes. Returns `null` when the id is unknown.
4395
+ * Collapses the two-step walk over `getComments().threads` +
4396
+ * `getTrackedChanges().revisions` that agents currently open-code.
4397
+ *
4398
+ * **Status:** @experimental (v2.x Phase 1).
4399
+ */
4400
+ findChangeById?(changeId: string): ChangeAnchor | null;
4401
+ /**
4402
+ * Track H T2 — filtered enumeration over comments + revisions.
4403
+ *
4404
+ * **Status:** @experimental (v2.x Phase 1).
4405
+ */
4406
+ findAllChanges?(filter?: ChangeFilter): ChangeAnchor[];
4407
+ /**
4408
+ * Track H T10 — typed id lookup over the comment sidebar snapshot.
4409
+ *
4410
+ * **Status:** @experimental (v2.x Phase 1).
4411
+ */
4412
+ getCommentSnapshotById?(commentId: string): CommentSidebarThreadSnapshot | null;
4413
+ /**
4414
+ * Track H T10 — typed id lookup over the tracked-changes snapshot.
4415
+ *
4416
+ * **Status:** @experimental (v2.x Phase 1).
4417
+ */
4418
+ getRevisionSnapshotById?(revisionId: string): TrackedChangeEntrySnapshot | null;
4419
+ /**
4420
+ * Track H T3 — sequenced batch of replace/insert/mark operations with
4421
+ * offset-shift protection. In `"back-to-front"` mode (default), edits
4422
+ * are sorted by descending `target.range.to` before apply so earlier
4423
+ * offsets are not shifted by later edits. In `"atomic"` mode the batch
4424
+ * runs inside a single `startAction` bracket and rolls back on failure.
4425
+ * Replaces the manual bytes-chain + sort pattern from CLM's
4426
+ * `generate_filled_document`.
4427
+ *
4428
+ * **Status:** @experimental (v2.x Phase 1).
4429
+ */
4430
+ applyBatchedEdits?(
4431
+ edits: BatchEditOperation[],
4432
+ options?: BatchEditOptions,
4433
+ ): Promise<BatchEditResult>;
4434
+ /**
4435
+ * Track H T4 — differential `WorkflowOverlay` patch. Never clobbers
4436
+ * engine-authored `scopes` or `workItems`; only the fields named in
4437
+ * the patch are touched. Replaces the documented read-merge-write
4438
+ * pattern around `getWorkflowOverlay()` + `setWorkflowOverlay()`.
4439
+ *
4440
+ * **Status:** @experimental (v2.x Phase 1).
4441
+ */
4442
+ patchWorkflowOverlay?(patch: WorkflowOverlayPatch): void;
4443
+ /**
4444
+ * Track H T5 — resolve `changeId` via `findChangeById`, build an
4445
+ * AI-explanation scope + candidate, and patch the overlay. One call
4446
+ * replaces ~60 lines of `annotate_document_with_explanations` glue.
4447
+ *
4448
+ * **Status:** @experimental (v2.x Phase 1).
4449
+ */
4450
+ attachAiExplanationScope?(
4451
+ input: AiExplanationScopeInput,
4452
+ ): AiExplanationScopeResult;
4453
+ /**
4454
+ * Track H T6 — one-shot `patchWorkflowOverlay` + `exportDocx`. Use
4455
+ * for AI-annotation pipelines that would otherwise run two stateless
4456
+ * round-trips through the same document.
4457
+ *
4458
+ * **Status:** @experimental (v2.x Phase 1).
4459
+ */
4460
+ exportDocxFromOverlayedSession?(
4461
+ patch: WorkflowOverlayPatch,
4462
+ exportOptions?: ExportDocxOptions,
4463
+ ): Promise<ExportResult>;
4464
+
3583
4465
  /**
3584
4466
  * Runtime-owned layout facet.
3585
4467
  *
@@ -3599,6 +4481,26 @@ export interface WordReviewEditorRef {
3599
4481
  * `ref.tables.apply(op)` with a typed discriminated union.
3600
4482
  */
3601
4483
  readonly tables: WordReviewEditorTablesFacet;
4484
+ /**
4485
+ * v2.0.0 — purpose-grouped projection of comment methods. Flat methods
4486
+ * (`addComment`, `resolveComment`, …) keep working. LLM workblocks should
4487
+ * prefer `editor.comments.*` to narrow their imports.
4488
+ */
4489
+ readonly comments: WordReviewEditorCommentsFacet;
4490
+ /** v2.0.0 — purpose-grouped projection of tracked-change methods. */
4491
+ readonly changes: WordReviewEditorChangesFacet;
4492
+ /** v2.0.0 — purpose-grouped projection of field / TOC operations. */
4493
+ readonly fields: WordReviewEditorFieldsFacet;
4494
+ /** v2.0.0 — purpose-grouped projection of document-level operations. */
4495
+ readonly document: WordReviewEditorDocumentFacet;
4496
+ /** v2.0.0 — purpose-grouped projection of workflow-scope + LLM helpers. */
4497
+ readonly scopes: WordReviewEditorScopesFacet;
4498
+ /**
4499
+ * v2.0.0 — diagnostic surface including the LLM error-catalog. Prefer
4500
+ * `editor.diagnostics.getCatalog()` at session-start to learn the
4501
+ * retry/fallback strategy for every code the editor can emit.
4502
+ */
4503
+ readonly diagnostics: WordReviewEditorDiagnosticsFacet;
3602
4504
  }
3603
4505
 
3604
4506
  /**
@@ -3663,6 +4565,13 @@ export interface WordReviewEditorChromeOptions {
3663
4565
  export interface WordReviewEditorProps {
3664
4566
  documentId: string;
3665
4567
  currentUser: EditorUser;
4568
+ /**
4569
+ * Optional host-provided shell content mounted above the editor's own
4570
+ * toolbar region. Harnesses and host apps use this to install a
4571
+ * `TwShellHeader` without rendering a parallel chrome outside the
4572
+ * editor workspace.
4573
+ */
4574
+ shellHeader?: ReactNode;
3666
4575
  ydoc?: import('yjs').Doc;
3667
4576
  awareness?: import("y-protocols/awareness").Awareness;
3668
4577
  /**
@@ -3789,8 +4698,23 @@ export interface WordReviewEditorProps {
3789
4698
  hostAdapter?: EditorHostAdapter;
3790
4699
  datastore?: EditorDatastoreAdapter;
3791
4700
  autosave?: AutosaveConfig;
4701
+ /**
4702
+ * Receives every `WordReviewEditorEvent` as it fires. Exceptions
4703
+ * thrown inside this callback are caught and logged non-fatally —
4704
+ * they do not propagate into the editor. Returning a Promise is
4705
+ * allowed but ignored.
4706
+ */
3792
4707
  onEvent?: (event: WordReviewEditorEvent) => void;
4708
+ /**
4709
+ * Receives non-fatal `EditorWarning` objects (e.g., compatibility
4710
+ * issues, detached anchors). Exceptions thrown here are swallowed.
4711
+ */
3793
4712
  onWarning?: (warning: EditorWarning) => void;
4713
+ /**
4714
+ * Receives fatal `EditorError` objects. Called once per error; the
4715
+ * editor enters a degraded state afterward. Exceptions thrown inside
4716
+ * this callback are swallowed to avoid double-fault loops.
4717
+ */
3794
4718
  onError?: (error: EditorError) => void;
3795
4719
  /**
3796
4720
  * Optional: opens the host's sidebar to the tracked-changes panel. When
@@ -3905,6 +4829,38 @@ export interface WordReviewEditorProps {
3905
4829
  * Capability id: `shortcut.last-edit`.
3906
4830
  */
3907
4831
  onLastEditRequested?: (context: ShortcutDelegationContext) => void;
4832
+ /**
4833
+ * design-close-chrome Phase 2 — density contract (designsystem §4.2).
4834
+ *
4835
+ * Controls the global `data-density` attribute that drives the
4836
+ * `--space-density-multiplier` cascade in `tokens.css`. When set,
4837
+ * the editor calls `useDensity().setDensity(value)` inside an effect;
4838
+ * when omitted, the hook reads the user's persisted preference from
4839
+ * `localStorage["wre.density"]` (defaulting to `"standard"`).
4840
+ *
4841
+ * @experimental The set of values (`"compact" | "standard" | "comfortable"`)
4842
+ * is stable; the effect-driven attribute write may move into a
4843
+ * theme-provider context in a future major.
4844
+ */
4845
+ density?: "compact" | "standard" | "comfortable";
4846
+ /**
4847
+ * design-close-chrome Phase 4 / R9 — host-supplied selection-tool
4848
+ * registry entries. Each entry is merged with the default
4849
+ * `SELECTION_TOOL_REGISTRY` via `resolveSelectionToolRegistry` (host
4850
+ * wins on id collision, merged list is precedence-sorted). Low-
4851
+ * precedence host entries (precedence < 10) can shadow the default
4852
+ * `suggestion-review` slot — useful for integrating a bespoke review
4853
+ * surface while keeping the remaining defaults.
4854
+ *
4855
+ * The entry's `id` must be a known `SelectionToolKind`; widening the
4856
+ * kind union to accept host render functions is coordinated with
4857
+ * Lane 8 (API ergonomics) and not part of this slice.
4858
+ *
4859
+ * @experimental
4860
+ */
4861
+ customSelectionTools?: ReadonlyArray<
4862
+ import("../ui/headless/chrome-registry").SelectionToolRegistryEntry
4863
+ >;
3908
4864
  }
3909
4865
 
3910
4866
  /**
@@ -4029,10 +4985,21 @@ export interface ResolveMetadataConflictInput {
4029
4985
  */
4030
4986
  export class EditorApiError extends Error {
4031
4987
  readonly code: string;
4032
- constructor(params: { code: string; message?: string }) {
4988
+ /**
4989
+ * v2.0.0 dual-error composite. Always populated when the editor itself
4990
+ * throws. Downstream code that re-throws `EditorApiError` (e.g. test
4991
+ * harnesses) may set this to `undefined`.
4992
+ */
4993
+ readonly diagnostic?: EditorDiagnostic;
4994
+ constructor(params: {
4995
+ code: string;
4996
+ message?: string;
4997
+ diagnostic?: EditorDiagnostic;
4998
+ }) {
4033
4999
  super(params.message ?? `EditorApiError: ${params.code}`);
4034
5000
  this.name = "EditorApiError";
4035
5001
  this.code = params.code;
5002
+ this.diagnostic = params.diagnostic;
4036
5003
  }
4037
5004
  }
4038
5005
 
@@ -4045,11 +5012,14 @@ export class EditorApiError extends Error {
4045
5012
  * Follows the fail-closed policy in collab-master-plan §1.6.
4046
5013
  */
4047
5014
  export class MetadataResolverMissingError extends Error {
4048
- constructor() {
5015
+ /** v2.0.0 dual-error composite (code `api.metadata_resolver_missing`). */
5016
+ readonly diagnostic?: EditorDiagnostic;
5017
+ constructor(diagnostic?: EditorDiagnostic) {
4049
5018
  super(
4050
5019
  "setMetadataPersistenceMode('external') requires a resolver — call " +
4051
5020
  "setScopeMetadataResolver(...) first.",
4052
5021
  );
4053
5022
  this.name = "MetadataResolverMissingError";
5023
+ this.diagnostic = diagnostic;
4054
5024
  }
4055
5025
  }