@agent-native/core-corpus 0.210.2 → 0.211.0

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 (192) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/actions/references/action-fields.md +5 -3
  3. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +41 -2
  4. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +4 -2
  5. package/corpus/templates/analytics/CHANGELOG.md +18 -0
  6. package/corpus/templates/analytics/actions/build-data-index.ts +11 -2
  7. package/corpus/templates/analytics/actions/configure-content-collection.ts +29 -4
  8. package/corpus/templates/analytics/actions/configure-first-party-events-model.ts +9 -7
  9. package/corpus/templates/analytics/actions/create-analytics-public-key.ts +4 -0
  10. package/corpus/templates/analytics/actions/estimate-content-signups-cost.ts +72 -0
  11. package/corpus/templates/analytics/actions/estimate-query-cost.ts +16 -134
  12. package/corpus/templates/analytics/actions/list-sigma-workbooks.ts +123 -42
  13. package/corpus/templates/analytics/actions/migrate-sigma-workbook.ts +20 -17
  14. package/corpus/templates/analytics/actions/revoke-analytics-public-key.ts +4 -0
  15. package/corpus/templates/analytics/app/components/dashboard/SigmaMigrationDialog.tsx +246 -680
  16. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
  17. package/corpus/templates/analytics/app/i18n/en-US.ts +54 -55
  18. package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +0 -1
  19. package/corpus/templates/analytics/app/pages/DataSources.tsx +56 -0
  20. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/filter-vars.ts +4 -3
  21. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +26 -8
  22. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/interpolate.ts +3 -1
  23. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/panel-cost-notice.ts +172 -0
  24. package/corpus/templates/analytics/app/pages/data-sources/SearchConsoleDetail.tsx +441 -0
  25. package/corpus/templates/analytics/changelog/2026-10-15-a-content-dashboard-lists-every-blog-article-with-its-author.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-10-15-data-sources-has-a-google-search-console-card-that-shows-the.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-10-16-the-content-dashboard-can-show-signups-per-blog-article.md +6 -0
  28. package/corpus/templates/analytics/changelog/2026-10-19-creating-or-revoking-a-public-analytics-key-now-asks-you-to-.md +6 -0
  29. package/corpus/templates/analytics/changelog/2026-10-19-search-sigma-workbooks-by-name-and-open-ones-a-teammate-alre.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-10-20-blog-signup-attribution-excludes-signups-before-the-first-vi.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-10-20-collapsed-analytics-navigation-starts-at-the-top.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-10-20-content-keeps-successful-coverage-dates-and-missing-day-gaps.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-10-20-private-github-repositories-can-be-indexed-with-your-connect.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-10-20-search-console-preserves-backfill-and-paused-collection.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-10-20-search-console-refreshes-historical-coverage-when-properties.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-10-20-search-console-setup-keeps-saved-properties-readable-and-sup.md +6 -0
  37. package/corpus/templates/analytics/seeds/dashboards/content-view.json +182 -0
  38. package/corpus/templates/analytics/server/db/schema.ts +1 -0
  39. package/corpus/templates/analytics/server/lib/bi-migration/external-dashboards-store.ts +56 -18
  40. package/corpus/templates/analytics/server/lib/bi-migration/unfinished-import.ts +64 -0
  41. package/corpus/templates/analytics/server/lib/builtin-dashboard-pass.ts +17 -2
  42. package/corpus/templates/analytics/server/lib/content-metrics/collect.ts +2 -0
  43. package/corpus/templates/analytics/server/lib/content-metrics/config.ts +92 -3
  44. package/corpus/templates/analytics/server/lib/content-metrics/legacy-content-view.json +172 -0
  45. package/corpus/templates/analytics/server/lib/content-metrics/migration.ts +2 -0
  46. package/corpus/templates/analytics/server/lib/content-metrics/steps/daily-metrics.ts +8 -3
  47. package/corpus/templates/analytics/server/lib/content-metrics/steps/search-console.ts +16 -3
  48. package/corpus/templates/analytics/server/lib/content-metrics/steps/signups.ts +240 -0
  49. package/corpus/templates/analytics/server/lib/content-metrics/store.ts +5 -0
  50. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +21 -0
  51. package/corpus/templates/analytics/server/lib/dashboard-panel-verification.ts +300 -5
  52. package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +2 -0
  53. package/corpus/templates/analytics/server/lib/dashboards-store.ts +28 -0
  54. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +128 -24
  55. package/corpus/templates/analytics/server/lib/google-analytics.ts +56 -16
  56. package/corpus/templates/analytics/server/lib/index-build-github.ts +5 -0
  57. package/corpus/templates/analytics/server/lib/provider-credentials.ts +47 -2
  58. package/corpus/templates/analytics/server/lib/query-cost-estimate.ts +184 -5
  59. package/corpus/templates/analytics/server/plugins/db.ts +9 -1
  60. package/corpus/templates/analytics/shared/builtin-dashboard-ids.ts +2 -0
  61. package/corpus/templates/analytics/shared/search-console-property.ts +78 -0
  62. package/corpus/templates/assets/.agents/skills/actions/references/action-fields.md +5 -3
  63. package/corpus/templates/brain/.agents/skills/actions/references/action-fields.md +5 -3
  64. package/corpus/templates/calendar/.agents/skills/actions/references/action-fields.md +5 -3
  65. package/corpus/templates/calendar/actions/delete-event.ts +1 -3
  66. package/corpus/templates/calendar/actions/delete-events.ts +1 -2
  67. package/corpus/templates/calendar/actions/event-action-helpers.ts +0 -4
  68. package/corpus/templates/calendar/actions/update-event.ts +2 -6
  69. package/corpus/templates/chat/.agents/skills/actions/references/action-fields.md +5 -3
  70. package/corpus/templates/clips/.agents/skills/actions/references/action-fields.md +5 -3
  71. package/corpus/templates/clips/CHANGELOG.md +11 -24
  72. package/corpus/templates/clips/actions/create-recording-upload.ts +5 -1
  73. package/corpus/templates/clips/app/components/player/chapter-list.tsx +7 -6
  74. package/corpus/templates/clips/app/components/player/comment-composer.tsx +5 -1
  75. package/corpus/templates/clips/app/components/player/player-controls.tsx +1 -0
  76. package/corpus/templates/clips/app/components/player/scrubber.tsx +4 -2
  77. package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
  78. package/corpus/templates/clips/app/lib/extension-auth.ts +70 -0
  79. package/corpus/templates/clips/app/root.tsx +22 -10
  80. package/corpus/templates/clips/app/routes/_app.notifications.tsx +3 -0
  81. package/corpus/templates/clips/app/routes/import.tsx +115 -110
  82. package/corpus/templates/clips/changelog/2026-10-16-agent-uploads-can-use-free-clips-storage.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-10-19-agents-see-a-clip-s-frames-as-soon-as-it-finishes-processing.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-10-19-chapter-list-times-now-match-the-player-s-clock-and-each-cha.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-10-19-editing-a-comment-puts-the-cursor-after-its-text-and-reply-o.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-10-19-youtube-import-followups.md +6 -0
  87. package/corpus/templates/clips/changelog/2026-10-20-locally-saved-desktop-recordings-now-appear-in-the-recovery-.md +6 -0
  88. package/corpus/templates/clips/desktop/src/app.tsx +29 -186
  89. package/corpus/templates/clips/desktop/src/components/RecordingRecovery.tsx +171 -16
  90. package/corpus/templates/clips/desktop/src/lib/record-first.ts +9 -32
  91. package/corpus/templates/clips/desktop/src/lib/recording-recovery.ts +30 -1
  92. package/corpus/templates/clips/server/lib/agent-frame-request.ts +5 -2
  93. package/corpus/templates/clips/server/lib/recording-upload-ticket.ts +8 -0
  94. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +2 -0
  95. package/corpus/templates/content/.agents/skills/actions/references/action-fields.md +5 -3
  96. package/corpus/templates/content/CHANGELOG.md +12 -0
  97. package/corpus/templates/content/actions/_content-database-personal-view.ts +5 -15
  98. package/corpus/templates/content/actions/_database-navigation.ts +3 -3
  99. package/corpus/templates/content/actions/_database-utils.ts +10 -22
  100. package/corpus/templates/content/actions/_database-view-setup.ts +16 -76
  101. package/corpus/templates/content/actions/create-comment-ai-suggestion.ts +93 -44
  102. package/corpus/templates/content/actions/export-document.ts +2 -14
  103. package/corpus/templates/content/actions/suggest-document-edit.ts +5 -7
  104. package/corpus/templates/content/actions/update-content-database-view.ts +2 -14
  105. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +86 -30
  106. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +64 -28
  107. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +6 -46
  108. package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +72 -7
  109. package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +292 -103
  110. package/corpus/templates/content/app/components/editor/ThreadSuggestion.tsx +147 -40
  111. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +108 -11
  112. package/corpus/templates/content/app/components/editor/database/ContentTable.tsx +2 -1
  113. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +150 -166
  114. package/corpus/templates/content/app/components/editor/database/database-cell-comments.tsx +515 -0
  115. package/corpus/templates/content/app/components/editor/database/database-item-comments.tsx +5 -43
  116. package/corpus/templates/content/app/components/editor/database/filter-sort.ts +8 -783
  117. package/corpus/templates/content/app/components/editor/live-editor-session.ts +5 -1
  118. package/corpus/templates/content/app/components/editor/page-draft-journal.ts +61 -1
  119. package/corpus/templates/content/app/components/editor/property-comments.tsx +35 -4
  120. package/corpus/templates/content/app/components/editor/property-date-format.ts +45 -0
  121. package/corpus/templates/content/app/components/editor/thread-suggestions.ts +30 -0
  122. package/corpus/templates/content/app/components/editor/useDocumentReconcileRecovery.ts +23 -4
  123. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +36 -10
  124. package/corpus/templates/content/app/global.css +23 -0
  125. package/corpus/templates/content/app/i18n-data.ts +1 -0
  126. package/corpus/templates/content/changelog/2026-10-16-opening-a-page-in-a-new-tab-while-another-tab-is-still-savin.md +6 -0
  127. package/corpus/templates/content/changelog/2026-10-16-typing-steadily-in-one-tab-no-longer-makes-another-open-tab-.md +6 -0
  128. package/corpus/templates/content/changelog/2026-10-19-database-views-can-filter-the-same-property-more-than-once-n.md +6 -0
  129. package/corpus/templates/content/changelog/2026-10-19-edits-made-from-a-block-s-menu-or-a-table-s-row-and-column-m.md +6 -0
  130. package/corpus/templates/content/changelog/2026-10-19-starting-a-comment-puts-the-cursor-in-the-comment-box-ready-.md +6 -0
  131. package/corpus/templates/content/changelog/2026-10-19-table-row-and-column-options-now-appear-for-the-row-or-colum.md +6 -0
  132. package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +5 -1
  133. package/corpus/templates/content/docs/product/capabilities/content.revision.suggestions.md +3 -1
  134. package/corpus/templates/content/e2e/helpers.ts +10 -0
  135. package/corpus/templates/content/shared/api.ts +18 -12
  136. package/corpus/templates/content/shared/database-query.ts +107 -13
  137. package/corpus/templates/content/shared/suggestion-diff.ts +35 -0
  138. package/corpus/templates/crm/.agents/skills/actions/references/action-fields.md +5 -3
  139. package/corpus/templates/design/.agents/skills/actions/references/action-fields.md +5 -3
  140. package/corpus/templates/design/CHANGELOG.md +2 -0
  141. package/corpus/templates/design/actions/delete-file.ts +1 -4
  142. package/corpus/templates/design/app/components/design/LayersPanel.tsx +10 -1
  143. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +24 -4
  144. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +14 -9
  145. package/corpus/templates/design/app/pages/design-editor/domains/use-editor-modes.ts +23 -2
  146. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +29 -0
  147. package/corpus/templates/design/changelog/2026-10-19-reply-and-edit-on-a-comment-in-the-sidebar-or-on-a-canvas-pi.md +6 -0
  148. package/corpus/templates/design/changelog/2026-10-20-comments-return-to-the-mode-they-came-from-and-layers-search.md +6 -0
  149. package/corpus/templates/design/e2e/global-setup.ts +185 -85
  150. package/corpus/templates/dispatch/.agents/skills/actions/references/action-fields.md +5 -3
  151. package/corpus/templates/dispatch/CHANGELOG.md +4 -0
  152. package/corpus/templates/dispatch/actions/apply-workspace-connection-setup.ts +4 -0
  153. package/corpus/templates/dispatch/actions/delete-workspace-connection.ts +4 -0
  154. package/corpus/templates/dispatch/actions/set-workspace-connection-grant.ts +4 -0
  155. package/corpus/templates/dispatch/actions/upsert-workspace-connection.ts +4 -0
  156. package/corpus/templates/dispatch/changelog/2026-10-19-vault-secrets-grants-link-tokens-app-access-and-workspace-co.md +6 -0
  157. package/corpus/templates/factory/.agents/skills/actions/references/action-fields.md +5 -3
  158. package/corpus/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +105 -33
  159. package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +128 -74
  160. package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +39 -11
  161. package/corpus/templates/forms/.agents/skills/actions/references/action-fields.md +5 -3
  162. package/corpus/templates/mail/.agents/skills/actions/references/action-fields.md +5 -3
  163. package/corpus/templates/mail/.agents/skills/contacts-and-crm/SKILL.md +22 -17
  164. package/corpus/templates/mail/AGENTS.md +1 -1
  165. package/corpus/templates/mail/CHANGELOG.md +14 -0
  166. package/corpus/templates/mail/actions/provider-api-request.ts +3 -3
  167. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +211 -54
  168. package/corpus/templates/mail/app/hooks/use-inbox-threads.ts +26 -2
  169. package/corpus/templates/mail/app/i18n/en-US.ts +5 -1
  170. package/corpus/templates/mail/app/lib/gong-connection.ts +27 -0
  171. package/corpus/templates/mail/app/lib/thread-cache.ts +110 -9
  172. package/corpus/templates/mail/app/root.tsx +10 -2
  173. package/corpus/templates/mail/changelog/2026-10-20-connected-gong-settings-now-open-the-shared-integration-mana.md +6 -0
  174. package/corpus/templates/mail/changelog/2026-10-20-gong-connection-details-now-match-the-call-data-available-in.md +6 -0
  175. package/corpus/templates/mail/changelog/2026-10-20-improve-gong-setup-with-a-click-to-connect-flow-and-permissi.md +6 -0
  176. package/corpus/templates/mail/changelog/2026-10-20-mail-lets-you-retry-when-it-cannot-check-your-gong-access.md +6 -0
  177. package/corpus/templates/mail/changelog/2026-10-20-mail-thread-cache-stays-isolated-when-mailbox-scope-changes.md +6 -0
  178. package/corpus/templates/mail/changelog/2026-10-20-the-inbox-and-recently-opened-threads-now-open-instantly-fro.md +6 -0
  179. package/corpus/templates/mail/server/handlers/emails.ts +9 -0
  180. package/corpus/templates/plan/.agents/skills/actions/references/action-fields.md +5 -3
  181. package/corpus/templates/plan/CHANGELOG.md +4 -0
  182. package/corpus/templates/plan/app/pages/PlansPage.tsx +173 -33
  183. package/corpus/templates/plan/changelog/2026-10-19-opening-a-comment-thread-puts-the-cursor-in-the-reply-box-an.md +6 -0
  184. package/corpus/templates/slides/.agents/skills/actions/references/action-fields.md +5 -3
  185. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +6 -42
  186. package/corpus/templates/slides/app/components/editor/FloatingToolbar.tsx +3 -7
  187. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +5 -14
  188. package/corpus/templates/slides/app/i18n/en-US.ts +0 -2
  189. package/corpus/templates/slides/app/pages/DeckEditor.tsx +27 -33
  190. package/corpus/templates/slides/scripts/edit-fidelity/run.ts +1 -3
  191. package/corpus/templates/tasks/.agents/skills/actions/references/action-fields.md +5 -3
  192. package/package.json +1 -1
@@ -171,6 +171,10 @@ import {
171
171
  PropertyCommentControl,
172
172
  usePropertyCommentRowState,
173
173
  } from "./property-comments";
174
+ import {
175
+ formatPropertyDate,
176
+ formatPropertyDateTime,
177
+ } from "./property-date-format";
174
178
 
175
179
  type TFunction = ReturnType<typeof useT>;
176
180
 
@@ -282,56 +286,12 @@ function slugify(value: string) {
282
286
  return slug || `option-${Date.now()}`;
283
287
  }
284
288
 
285
- function formatDate(value: string) {
286
- if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
287
- const [year, month, day] = value.split("-").map(Number);
288
- return new Intl.DateTimeFormat(undefined, {
289
- month: "short",
290
- day: "numeric",
291
- year: "numeric",
292
- }).format(new Date(year, month - 1, day));
293
- }
294
-
295
- const date = new Date(value);
296
- if (Number.isNaN(date.getTime())) return value;
297
- return new Intl.DateTimeFormat(undefined, {
298
- month: "short",
299
- day: "numeric",
300
- year: "numeric",
301
- }).format(date);
302
- }
303
-
304
- function formatDateTime(value: string) {
305
- if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(value)) {
306
- const [datePart, timePart] = value.split("T");
307
- const [year, month, day] = datePart.split("-").map(Number);
308
- const [hour, minute] = timePart.split(":").map(Number);
309
- return new Intl.DateTimeFormat(undefined, {
310
- month: "short",
311
- day: "numeric",
312
- year: "numeric",
313
- hour: "numeric",
314
- minute: "2-digit",
315
- }).format(new Date(year, month - 1, day, hour, minute));
316
- }
317
-
318
- const date = new Date(value);
319
- if (Number.isNaN(date.getTime())) return value;
320
- return new Intl.DateTimeFormat(undefined, {
321
- month: "short",
322
- day: "numeric",
323
- year: "numeric",
324
- hour: "numeric",
325
- minute: "2-digit",
326
- }).format(date);
327
- }
328
-
329
289
  function formatPropertyDateDisplayValue(
330
290
  value: DocumentProperty["value"],
331
291
  t?: TFunction,
332
292
  ) {
333
293
  const includeTime = documentPropertyDateIncludesTime(value);
334
- const formatter = includeTime ? formatDateTime : formatDate;
294
+ const formatter = includeTime ? formatPropertyDateTime : formatPropertyDate;
335
295
  const start = documentPropertyDatePart(value, "start");
336
296
  const end = documentPropertyDatePart(value, "end");
337
297
  if (!start) return tWithFallback(t, "editor.properties.empty", "Empty");
@@ -392,7 +352,7 @@ export function displayValue(
392
352
  }
393
353
 
394
354
  if (type === "created_time" || type === "last_edited_time") {
395
- return <span>{formatDateTime(propertyText(value))}</span>;
355
+ return <span>{formatPropertyDateTime(propertyText(value))}</span>;
396
356
  }
397
357
 
398
358
  if (type === "person") {
@@ -37,6 +37,7 @@ import { DocumentEditorSkeleton } from "./DocumentEditorSkeleton";
37
37
  import { LiveEditorSessionContext } from "./live-editor-session";
38
38
  import {
39
39
  clearPageDraftJournal,
40
+ liveDraftWriterIds,
40
41
  readPageDraftJournal,
41
42
  sweepLegacyRetainedPageDraftMarkers,
42
43
  writePageDraftJournal,
@@ -110,6 +111,20 @@ export function PageDraftRecovery({
110
111
  "checking" | "promoting" | "waiting_sql" | "ready" | "failed"
111
112
  >("checking");
112
113
  const [journalRevision, setJournalRevision] = useState(0);
114
+ // Another tab's open editor settles its own journal entries; replaying one
115
+ // here races its save queue and sends a save for text nobody typed here.
116
+ // A query only knows the editors open when it ran, so it holds for the
117
+ // journal entry and SQL draft it was taken for; a tab opened since writes
118
+ // entries it misses.
119
+ const [liveWriters, setLiveWriters] = useState<{
120
+ scopeKey: string;
121
+ entryKey: string | null;
122
+ draftKey: string | null;
123
+ writerIds: ReadonlySet<string>;
124
+ } | null>(null);
125
+ const scopeLiveWriters =
126
+ liveWriters && liveWriters.scopeKey === scopeKey ? liveWriters : null;
127
+ const skippedWriterIds = scopeLiveWriters?.writerIds;
113
128
  const journalAttemptRef = useRef<string | null>(null);
114
129
  const automaticRecoveryRef = useRef<string | null>(null);
115
130
  const automaticLegacyRecoveryRef = useRef<string | null>(null);
@@ -124,6 +139,17 @@ export function PageDraftRecovery({
124
139
  drafts.data.draft.editorSessionId === liveEditorSessionId
125
140
  ? null
126
141
  : drafts.data?.draft;
142
+ // So does an editor open in another tab; settling its draft here would move
143
+ // text it is still saving to History. Its draft can outlive its journal
144
+ // entry, or have none when that write failed, so the draft is checked too.
145
+ const draftKey = draft?.editorSessionId
146
+ ? `${draft.editorSessionId}:${draft.editGeneration}:${draft.version}`
147
+ : null;
148
+ const draftLivenessKnown =
149
+ draftKey === null || scopeLiveWriters?.draftKey === draftKey;
150
+ const draftOpenElsewhere = Boolean(
151
+ draft?.editorSessionId && skippedWriterIds?.has(draft.editorSessionId),
152
+ );
127
153
  // No scope until the session read returns; the session cache expires, so a
128
154
  // page opened later can mount before then. Unverified until it does.
129
155
  const scopeVerified = scopeKey !== null && verifiedScopeKey === scopeKey;
@@ -190,11 +216,40 @@ export function PageDraftRecovery({
190
216
  };
191
217
  let entry;
192
218
  try {
193
- entry = readPageDraftJournal(scope);
219
+ entry = readPageDraftJournal(scope, skippedWriterIds);
194
220
  } catch {
195
221
  setJournalState("failed");
196
222
  return;
197
223
  }
224
+ const entryKey = entry
225
+ ? `${entry.scope.writerId}:${entry.snapshot.editGeneration}:${entry.writtenAt}`
226
+ : null;
227
+ if (
228
+ scopeKey &&
229
+ ((entryKey !== null && scopeLiveWriters?.entryKey !== entryKey) ||
230
+ !draftLivenessKnown)
231
+ ) {
232
+ let cancelled = false;
233
+ void liveDraftWriterIds().then(
234
+ (writerIds) => {
235
+ // Without Web Locks no writer reads as live, so every entry
236
+ // replays, as it did before writer locks.
237
+ if (!cancelled)
238
+ setLiveWriters({
239
+ scopeKey,
240
+ entryKey,
241
+ draftKey,
242
+ writerIds: writerIds ?? new Set(),
243
+ });
244
+ },
245
+ () => {
246
+ if (!cancelled) setJournalState("failed");
247
+ },
248
+ );
249
+ return () => {
250
+ cancelled = true;
251
+ };
252
+ }
198
253
  if (!entry) {
199
254
  sweepLegacyRetainedPageDraftMarkers();
200
255
  setJournalState("ready");
@@ -471,6 +526,8 @@ export function PageDraftRecovery({
471
526
  editorReleased,
472
527
  journalRevision,
473
528
  journalState,
529
+ scopeKey,
530
+ scopeLiveWriters,
474
531
  scopeVerified,
475
532
  session?.email,
476
533
  session?.orgId,
@@ -690,6 +747,8 @@ export function PageDraftRecovery({
690
747
  if (
691
748
  !draft ||
692
749
  !hasEditIdentity ||
750
+ !draftLivenessKnown ||
751
+ draftOpenElsewhere ||
693
752
  busy ||
694
753
  failure ||
695
754
  journalState === "checking" ||
@@ -712,11 +771,14 @@ export function PageDraftRecovery({
712
771
  }
713
772
  if (session?.email) {
714
773
  try {
715
- const journal = readPageDraftJournal({
716
- accountId: session.email.trim().toLowerCase(),
717
- orgId: session.orgId ?? null,
718
- documentId: document.id,
719
- });
774
+ const journal = readPageDraftJournal(
775
+ {
776
+ accountId: session.email.trim().toLowerCase(),
777
+ orgId: session.orgId ?? null,
778
+ documentId: document.id,
779
+ },
780
+ skippedWriterIds,
781
+ );
720
782
  if (
721
783
  journal?.snapshot.title === draft.title &&
722
784
  journal.snapshot.content === draft.content
@@ -733,12 +795,15 @@ export function PageDraftRecovery({
733
795
  busy,
734
796
  document,
735
797
  draft,
798
+ draftLivenessKnown,
799
+ draftOpenElsewhere,
736
800
  failure,
737
801
  hasEditIdentity,
738
802
  journalState,
739
803
  scopeVerified,
740
804
  session?.email,
741
805
  session?.orgId,
806
+ skippedWriterIds,
742
807
  ]);
743
808
 
744
809
  // Keep the editor at one tree position so a notice never remounts it.
@@ -795,7 +860,7 @@ export function PageDraftRecovery({
795
860
  }
796
861
  />
797
862
  );
798
- if (!draft) return withNotice(null);
863
+ if (!draft || draftOpenElsewhere) return withNotice(null);
799
864
  // Legacy drafts are preserved automatically; that path toasts once.
800
865
  if (!hasEditIdentity && !failure) return withNotice(null);
801
866
  if (!failure)