@arbidocs/react 0.5.86 → 0.5.88

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 (117) hide show
  1. package/README.md +2 -3
  2. package/dist/artifacts/index.cjs +46 -48
  3. package/dist/artifacts/index.cjs.map +1 -1
  4. package/dist/artifacts/index.js +7 -9
  5. package/dist/artifacts/index.js.map +1 -1
  6. package/dist/calls/livekit/index.cjs +60 -62
  7. package/dist/calls/livekit/index.cjs.map +1 -1
  8. package/dist/calls/livekit/index.js +6 -8
  9. package/dist/calls/livekit/index.js.map +1 -1
  10. package/dist/{chunk-Z3LLUO32.cjs → chunk-5NOZDH3F.cjs} +12 -2
  11. package/dist/chunk-5NOZDH3F.cjs.map +1 -0
  12. package/dist/{chunk-WQY3RQ6G.js → chunk-73ENECAT.js} +5 -6
  13. package/dist/{chunk-LUDIYWT7.cjs.map → chunk-73ENECAT.js.map} +1 -1
  14. package/dist/{chunk-2Y2WOIHH.cjs → chunk-AOPGD23L.cjs} +60 -148
  15. package/dist/chunk-AOPGD23L.cjs.map +1 -0
  16. package/dist/{chunk-G4Z3IP4J.js → chunk-BF5KW5ZI.js} +3 -17
  17. package/dist/chunk-BF5KW5ZI.js.map +1 -0
  18. package/dist/{chunk-TK7ERJPE.js → chunk-BFNY3RZG.js} +22 -12
  19. package/dist/chunk-BFNY3RZG.js.map +1 -0
  20. package/dist/{chunk-U4PWVSCT.cjs → chunk-C4WODQGO.cjs} +24 -11
  21. package/dist/chunk-C4WODQGO.cjs.map +1 -0
  22. package/dist/{chunk-E7VD5WNY.cjs → chunk-DS7NTSKH.cjs} +41 -74
  23. package/dist/chunk-DS7NTSKH.cjs.map +1 -0
  24. package/dist/{chunk-JT7PN7JH.js → chunk-DU2P354H.js} +6 -37
  25. package/dist/chunk-DU2P354H.js.map +1 -0
  26. package/dist/{chunk-TAVS54EN.cjs → chunk-GKWMT64A.cjs} +6 -6
  27. package/dist/{chunk-TAVS54EN.cjs.map → chunk-GKWMT64A.cjs.map} +1 -1
  28. package/dist/{chunk-AXKHDLBB.cjs → chunk-HEVPIVF2.cjs} +15 -15
  29. package/dist/{chunk-AXKHDLBB.cjs.map → chunk-HEVPIVF2.cjs.map} +1 -1
  30. package/dist/{chunk-XPLD4LFC.js → chunk-KTXZ222T.js} +6 -91
  31. package/dist/chunk-KTXZ222T.js.map +1 -0
  32. package/dist/{chunk-PXWKJI4K.cjs → chunk-LBAG7KL7.cjs} +35 -261
  33. package/dist/chunk-LBAG7KL7.cjs.map +1 -0
  34. package/dist/{chunk-CSPAEVZS.js → chunk-MS43RNXM.js} +5 -5
  35. package/dist/{chunk-CSPAEVZS.js.map → chunk-MS43RNXM.js.map} +1 -1
  36. package/dist/{chunk-OC7F5SNA.cjs → chunk-MXP4O4DI.cjs} +5 -5
  37. package/dist/{chunk-OC7F5SNA.cjs.map → chunk-MXP4O4DI.cjs.map} +1 -1
  38. package/dist/{chunk-ZWFMFOGP.cjs → chunk-NDIKMOBJ.cjs} +4 -4
  39. package/dist/{chunk-ZWFMFOGP.cjs.map → chunk-NDIKMOBJ.cjs.map} +1 -1
  40. package/dist/{chunk-XAEVT7ZM.js → chunk-NNAJLY6B.js} +34 -257
  41. package/dist/chunk-NNAJLY6B.js.map +1 -0
  42. package/dist/{chunk-LUDIYWT7.cjs → chunk-QLRDHLWR.cjs} +72 -73
  43. package/dist/chunk-QLRDHLWR.cjs.map +1 -0
  44. package/dist/{chunk-DZUBZ45Y.cjs → chunk-RLSBRZ6Z.cjs} +2 -17
  45. package/dist/chunk-RLSBRZ6Z.cjs.map +1 -0
  46. package/dist/{chunk-VGAA7AFS.js → chunk-S3OGDLDC.js} +4 -13
  47. package/dist/chunk-S3OGDLDC.js.map +1 -0
  48. package/dist/{chunk-NNWMHMEC.js → chunk-UW2SGTI5.js} +3 -3
  49. package/dist/{chunk-NNWMHMEC.js.map → chunk-UW2SGTI5.js.map} +1 -1
  50. package/dist/{chunk-QRCMKEE6.js → chunk-VSCU7K4V.js} +11 -3
  51. package/dist/chunk-VSCU7K4V.js.map +1 -0
  52. package/dist/{chunk-C44GO33B.js → chunk-WL2Y2T47.js} +3 -3
  53. package/dist/{chunk-C44GO33B.js.map → chunk-WL2Y2T47.js.map} +1 -1
  54. package/dist/{chunk-47YVW3J4.js → chunk-YQBDEOVE.js} +4 -4
  55. package/dist/{chunk-47YVW3J4.js.map → chunk-YQBDEOVE.js.map} +1 -1
  56. package/dist/{chunk-Q6U7ALNV.cjs → chunk-ZHXYFJIA.cjs} +44 -54
  57. package/dist/chunk-ZHXYFJIA.cjs.map +1 -0
  58. package/dist/document-tools/core.cjs +100 -110
  59. package/dist/document-tools/core.d.cts +3 -78
  60. package/dist/document-tools/core.d.ts +3 -78
  61. package/dist/document-tools/core.js +5 -7
  62. package/dist/document-tools/index.cjs +102 -112
  63. package/dist/document-tools/index.cjs.map +1 -1
  64. package/dist/document-tools/index.d.cts +2 -2
  65. package/dist/document-tools/index.d.ts +2 -2
  66. package/dist/document-tools/index.js +6 -8
  67. package/dist/document-tools/index.js.map +1 -1
  68. package/dist/index.cjs +1740 -2305
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/{index.d-BDcwpFVa.d.cts → index.d-1_bJB-Yl.d.cts} +1 -58
  71. package/dist/{index.d-BDcwpFVa.d.ts → index.d-1_bJB-Yl.d.ts} +1 -58
  72. package/dist/{index.d-Deqz5-pF.d.ts → index.d-ChaR6kMc.d.cts} +1 -6
  73. package/dist/{index.d-Deqz5-pF.d.cts → index.d-ChaR6kMc.d.ts} +1 -6
  74. package/dist/index.d.cts +184 -1423
  75. package/dist/index.d.ts +184 -1423
  76. package/dist/index.js +281 -799
  77. package/dist/index.js.map +1 -1
  78. package/dist/{query-keys.d-Dm0NL9nr.d.cts → query-keys.d-D6SAUl7S.d.cts} +0 -9
  79. package/dist/{query-keys.d-Dm0NL9nr.d.ts → query-keys.d-D6SAUl7S.d.ts} +0 -9
  80. package/dist/shell/index.cjs +48 -53
  81. package/dist/shell/index.d.cts +1 -1
  82. package/dist/shell/index.d.ts +1 -1
  83. package/dist/shell/index.js +4 -5
  84. package/dist/ui/index.cjs +156 -169
  85. package/dist/ui/index.d.cts +1 -1
  86. package/dist/ui/index.d.ts +1 -1
  87. package/dist/ui/index.js +3 -4
  88. package/dist/viewers/index.cjs +0 -120
  89. package/dist/viewers/index.cjs.map +1 -1
  90. package/dist/viewers/index.d.cts +3 -40
  91. package/dist/viewers/index.d.ts +3 -40
  92. package/dist/viewers/index.js +1 -120
  93. package/dist/viewers/index.js.map +1 -1
  94. package/package.json +3 -3
  95. package/dist/chunk-2Y2WOIHH.cjs.map +0 -1
  96. package/dist/chunk-CPZ36AQS.js +0 -11
  97. package/dist/chunk-CPZ36AQS.js.map +0 -1
  98. package/dist/chunk-DZUBZ45Y.cjs.map +0 -1
  99. package/dist/chunk-E7VD5WNY.cjs.map +0 -1
  100. package/dist/chunk-G4Z3IP4J.js.map +0 -1
  101. package/dist/chunk-JT7PN7JH.js.map +0 -1
  102. package/dist/chunk-PXWKJI4K.cjs.map +0 -1
  103. package/dist/chunk-Q6U7ALNV.cjs.map +0 -1
  104. package/dist/chunk-QRCMKEE6.js.map +0 -1
  105. package/dist/chunk-RCKA7BEF.cjs +0 -14
  106. package/dist/chunk-RCKA7BEF.cjs.map +0 -1
  107. package/dist/chunk-TK7ERJPE.js.map +0 -1
  108. package/dist/chunk-U4PWVSCT.cjs.map +0 -1
  109. package/dist/chunk-VGAA7AFS.js.map +0 -1
  110. package/dist/chunk-VGMMK5OM.cjs +0 -26
  111. package/dist/chunk-VGMMK5OM.cjs.map +0 -1
  112. package/dist/chunk-VGO77X5U.js +0 -22
  113. package/dist/chunk-VGO77X5U.js.map +0 -1
  114. package/dist/chunk-WQY3RQ6G.js.map +0 -1
  115. package/dist/chunk-XAEVT7ZM.js.map +0 -1
  116. package/dist/chunk-XPLD4LFC.js.map +0 -1
  117. package/dist/chunk-Z3LLUO32.cjs.map +0 -1
@@ -195,20 +195,6 @@ function useMessageChatArtifact(messageId) {
195
195
  () => void 0
196
196
  );
197
197
  }
198
- function useConversationChatArtifact(conversationId) {
199
- return react.useSyncExternalStore(
200
- subscribe,
201
- () => {
202
- if (!conversationId) return void 0;
203
- for (let i = order.length - 1; i >= 0; i--) {
204
- const artifact = artifacts[order[i]];
205
- if (artifact?.conversationId === conversationId) return artifact;
206
- }
207
- return void 0;
208
- },
209
- () => void 0
210
- );
211
- }
212
198
 
213
199
  Object.defineProperty(exports, "toast", {
214
200
  enumerable: true,
@@ -226,8 +212,7 @@ exports.recordChatArtifact = recordChatArtifact;
226
212
  exports.seedNotifications = seedNotifications;
227
213
  exports.selectUnread = selectUnread;
228
214
  exports.useChatArtifact = useChatArtifact;
229
- exports.useConversationChatArtifact = useConversationChatArtifact;
230
215
  exports.useMessageChatArtifact = useMessageChatArtifact;
231
216
  exports.useNotify = useNotify;
232
- //# sourceMappingURL=chunk-DZUBZ45Y.cjs.map
233
- //# sourceMappingURL=chunk-DZUBZ45Y.cjs.map
217
+ //# sourceMappingURL=chunk-RLSBRZ6Z.cjs.map
218
+ //# sourceMappingURL=chunk-RLSBRZ6Z.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/notifications/notify-store.ts","../src/chat/chat-artifacts.ts"],"names":["create","renderToStaticMarkup","toast","saved","useSyncExternalStore"],"mappings":"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","file":"chunk-RLSBRZ6Z.cjs","sourcesContent":["/**\n * The one notification history: every `notify.*` call pops a transient toast (rendered by\n * <Toaster/>, on sonner) and, unless `{ record: false }`, records an entry. The same entries feed\n * the topbar bell (<NotificationBell/>), its unread badge and a host's notification page; backend\n * bridges reconcile their own slices into it with {@link syncSource}.\n *\n * notify.success('Saved') // toast + entry\n * notify.error('Upload failed', { record: false }) // toast only\n * notify.info('Opening workspace…', { ambient: true }) // a log line: never badges\n *\n * sonner owns the transient toast lifecycle (stacking, timing, dismissal); this store owns the\n * history, the mute switch and what a host configures once (workspace glyph and link, see\n * {@link configureNotify}; persistence, see {@link persistNotifyHistory}). Brand-neutral: no seed\n * data, no app imports. For full sonner power the raw `toast` is re-exported.\n */\nimport { type ReactNode } from 'react'\nimport { renderToStaticMarkup } from 'react-dom/server'\n// This module IS the sanctioned toast engine home — the app-level rule that\n// steers callers to notify() doesn't apply here.\n// eslint-disable-next-line no-restricted-imports\nimport { toast } from 'sonner'\nimport { create } from 'zustand'\n\nexport { toast }\n\nexport type NotifyVariant = 'success' | 'error' | 'info' | 'warning'\n\nexport interface AppNotification {\n id: string\n title: string\n description?: string\n variant: NotifyVariant\n /** Epoch ms the entry was recorded. */\n ts: number\n read: boolean\n /** Optional in-app link the entry deep-links to (passed to the bell's onNavigate). */\n href?: string\n /** Optional click action — wins over `href` when both are present. Session\n * history only: never persisted, so a closure is safe here. */\n onSelect?: () => void\n /** The label of the action `onSelect` runs (\"Reply\", \"View\"). */\n actionLabel?: string\n /** Workspace the entry belongs to. */\n workspaceId?: string\n /** Markup of a rich (non-string) toast message, for a log that shows it as it was toasted. */\n html?: string\n /** Routine session activity (\"Opening workspace…\", \"Saved\") — kept for the\n * log but not something that demands attention: excluded from the unread\n * badge and from the bell's list. */\n ambient?: boolean\n /** Where the entry comes from. Session entries (`notify.*`) have none; a\n * backend bridge stamps its own (e.g. 'server') so {@link syncSource} can\n * replace exactly its slice on every refetch without touching the rest. */\n source?: string\n}\n\nexport interface NotifyOptions {\n /** Shown under the title in the toast; a string description is also recorded. */\n description?: ReactNode\n /** Record an entry in the history (default true). False pops the toast only — for an event\n * whose entry arrives another way (a server-persisted notification synced by a bridge). */\n record?: boolean\n /** Pop the transient toast (default true unless muted). False records the entry only. */\n toast?: boolean\n /** Recorded title for a rich (non-string) toast title. Default: the string title, else the\n * rich title's text. */\n recordTitle?: string\n /** Recorded markup for a rich toast title (default: the title rendered to static markup). */\n html?: string\n href?: string\n /** Workspace the notification belongs to: its glyph shows in the toast and its link is the\n * entry's default `href` (both as configured with {@link configureNotify}). */\n workspaceId?: string\n duration?: number\n /** A toast action button (sonner). Clicking the entry runs it too. */\n action?: { label: ReactNode; onClick: () => void }\n /** Override the toast glyph (sonner). */\n icon?: ReactNode\n /** Extra class on the toast (sonner). */\n className?: string\n /** Record as routine session activity (see {@link AppNotification.ambient}): born read. */\n ambient?: boolean\n}\n\n/** Session entries kept (oldest dropped first) — a safety net against pathological growth; a\n * large upload can log many entries, so it is generous. Source slices are bounded by their source. */\nexport const MAX_SESSION_NOTIFICATIONS = 5000\n\ninterface NotifyState {\n notifications: AppNotification[]\n /** Toasts are muted: entries are still recorded — the history is what the user comes back to. */\n muted: boolean\n setMuted: (muted: boolean) => void\n markRead: (id: string) => void\n markAllRead: () => void\n removeNotification: (id: string) => void\n removeNotifications: (ids: readonly string[]) => void\n clearNotifications: () => void\n /** Replace the history (e.g. seed a demo/initial set). */\n seed: (items: AppNotification[]) => void\n /** Record an entry (used by `notify.*`; sonner renders the toast). */\n record: (note: AppNotification) => void\n /** Reconcile one source's slice with fresh truth (e.g. a backend list on\n * every refetch): entries stamped with `source` are replaced wholesale —\n * including their read state, which the source owns — while entries from\n * other sources (session activity) stay untouched. Newest first. */\n syncSource: (source: string, items: AppNotification[]) => void\n}\n\nlet seq = 0\nconst uid = () => `n${Date.now().toString(36)}${(seq++).toString(36)}`\n\n/** Keep at most {@link MAX_SESSION_NOTIFICATIONS} session entries (newest first). */\nfunction capSession(items: AppNotification[]): AppNotification[] {\n let session = 0\n return items.filter((n) => n.source || ++session <= MAX_SESSION_NOTIFICATIONS)\n}\n\nexport const useNotify = create<NotifyState>((set) => ({\n notifications: [],\n muted: false,\n setMuted: (muted) => set({ muted }),\n markRead: (id) =>\n set((s) => ({\n notifications: s.notifications.map((n) => (n.id === id ? { ...n, read: true } : n)),\n })),\n markAllRead: () =>\n set((s) => ({ notifications: s.notifications.map((n) => ({ ...n, read: true })) })),\n removeNotification: (id) =>\n set((s) => ({ notifications: s.notifications.filter((n) => n.id !== id) })),\n removeNotifications: (ids) => {\n const drop = new Set(ids)\n set((s) => ({ notifications: s.notifications.filter((n) => !drop.has(n.id)) }))\n },\n clearNotifications: () => set({ notifications: [] }),\n seed: (items) => set({ notifications: items }),\n record: (note) => set((s) => ({ notifications: capSession([note, ...s.notifications]) })),\n syncSource: (source, items) =>\n set((s) => ({\n notifications: [\n ...items.map((n) => ({ ...n, source })),\n ...s.notifications.filter((n) => n.source !== source),\n ].sort((a, b) => b.ts - a.ts),\n })),\n}))\n\n/** What a host configures once for every `notify.*` call. */\nexport interface NotifyConfig {\n /** The toast glyph of a notification that names a workspace. */\n workspaceIcon?: (workspaceId: string) => ReactNode\n /** The default link of an entry that names a workspace. */\n workspaceHref?: (workspaceId: string) => string | undefined\n /** The default of {@link NotifyOptions.ambient} for calls that do not say: a host whose own\n * toasts are mostly confirmations (\"Saved\") records them as log lines, and passes\n * `ambient: false` for what should claim attention. Default false. */\n ambient?: boolean\n}\n\nlet config: NotifyConfig = {}\n\n/** Set the host's workspace glyph and link (merged into what is configured). */\nexport function configureNotify(next: NotifyConfig): void {\n config = { ...config, ...next }\n}\n\nfunction richMarkup(title: ReactNode): string | undefined {\n try {\n return renderToStaticMarkup(title)\n } catch {\n return undefined\n }\n}\n\nconst textOf = (html: string | undefined) =>\n (html ?? '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n\n/** Ergonomic helper — `notify.success('Saved')` — toast (sonner) + optional entry. */\nfunction make(variant: NotifyVariant) {\n return (title: ReactNode, opts: NotifyOptions = {}): string => {\n const { workspaceId } = opts\n const ambient = opts.ambient ?? config.ambient ?? false\n if (opts.toast !== false && !useNotify.getState().muted) {\n toast[variant](title, {\n description: opts.description,\n duration: opts.duration,\n action: opts.action,\n icon: opts.icon ?? (workspaceId ? config.workspaceIcon?.(workspaceId) : undefined),\n className: opts.className,\n })\n }\n const id = uid()\n if (opts.record !== false) {\n const html =\n opts.html ?? (typeof title === 'string' || title == null ? undefined : richMarkup(title))\n useNotify.getState().record({\n id,\n // A rich toast still needs a READABLE title — \"Passage copied: gamma-services p.1\",\n // not \"Notification\" — so it comes from the rendered markup, tags stripped.\n title:\n opts.recordTitle ?? (typeof title === 'string' ? title : textOf(html) || 'Notification'),\n description: typeof opts.description === 'string' ? opts.description : undefined,\n variant,\n ts: Date.now(),\n // Ambient activity is a log line, not a claim on attention: it never wears an unread dot.\n read: ambient,\n // Clicking the entry goes where the notification points: its action (when it has one),\n // an explicit link, or the workspace it happened in.\n href: opts.href ?? (workspaceId ? config.workspaceHref?.(workspaceId) : undefined),\n onSelect: opts.action?.onClick,\n actionLabel: opts.action ? String(opts.action.label) : undefined,\n workspaceId,\n html,\n ambient,\n })\n }\n return id\n }\n}\nexport const notify = {\n success: make('success'),\n error: make('error'),\n info: make('info'),\n warning: make('warning'),\n}\n\n/** Replace the history — inject a seed/initial set. */\nexport function seedNotifications(items: AppNotification[]): void {\n useNotify.getState().seed(items)\n}\n\ninterface SavedHistory {\n muted?: boolean\n notifications?: AppNotification[]\n}\n\n/**\n * Keep the session history and the mute switch across reloads in `storage` under `key`: restores\n * them now and saves every change. Source slices are not saved (their source re-syncs them), and\n * neither are actions — a closure does not survive a reload. Returns the unsubscribe.\n */\nexport function persistNotifyHistory(\n key: string,\n storage: Pick<Storage, 'getItem' | 'setItem'> | undefined = globalThis.localStorage\n): () => void {\n if (!storage) return () => {}\n try {\n const saved = JSON.parse(storage.getItem(key) ?? 'null') as SavedHistory | null\n if (saved) {\n const known = new Set(useNotify.getState().notifications.map((n) => n.id))\n useNotify.setState((s) => ({\n muted: saved.muted ?? s.muted,\n notifications: capSession(\n [\n ...s.notifications,\n ...(saved.notifications ?? []).filter((n) => !n.source && !known.has(n.id)),\n ].sort((a, b) => b.ts - a.ts)\n ),\n }))\n }\n } catch {\n // Unreadable or blocked storage: start empty.\n }\n let saved: AppNotification[] = []\n let savedMuted: boolean | undefined\n return useNotify.subscribe((s) => {\n const session = s.notifications.filter((n) => !n.source)\n // A backend re-sync or a read change elsewhere leaves the session slice as it was.\n if (\n s.muted === savedMuted &&\n session.length === saved.length &&\n session.every((n, i) => n === saved[i])\n )\n return\n saved = session\n savedMuted = s.muted\n // JSON drops the undefined fields: an action's closure cannot be saved, nor its label alone.\n const notifications = session.map((n) => ({\n ...n,\n onSelect: undefined,\n actionLabel: undefined,\n }))\n try {\n storage.setItem(key, JSON.stringify({ muted: s.muted, notifications }))\n } catch {\n // Full or blocked storage: the in-memory history still works.\n }\n })\n}\n\n/** Unread count selector for the topbar bell — ambient session activity never\n * demands attention, so it never counts. */\nexport const selectUnread = (s: NotifyState): number =>\n s.notifications.filter((n) => !n.read && !n.ambient).length\n\n/** Default glyph colour per variant (raw palette, override via `toneClassNames`). */\nexport const DEFAULT_NOTIFY_TONE: Record<NotifyVariant, string> = {\n success: 'text-green-600',\n error: 'text-destructive',\n warning: 'text-amber-500',\n info: 'text-blue-500',\n}\n","import { useSyncExternalStore } from 'react'\nimport type { ArtifactEvent } from '@arbidocs/sdk/browser'\n\n/**\n * The documents the assistant is writing (or wrote) in this tab's chats, as their artifact events\n * stream in: the chat engine records every one (`recordChatArtifact`), before the host's\n * `chat.onArtifact` shows it. One store for every surface that shows a draft as it is written: the\n * answer's artifact card, the document viewer, and a drafting chat's document pane.\n *\n * A module-level store, like the open-document registry: a chat and a viewer agree wherever they\n * sit in the tree. It holds what streamed in this tab only; a saved draft is read from the\n * documents list. Cleared on sign-out (`clearChatArtifacts`).\n */\n\n/** An artifact as it streams: what the events said so far. */\nexport interface ChatArtifact {\n /** The document it is written into (`doc-…`). */\n docExtId: string\n title: string\n /** The content so far (Markdown, or the html/react source of a live artifact). */\n content: string\n /**\n * `markdown` / `text` are document drafts (stored by the server as Word documents); `html` /\n * `react` are live artifacts; `image` is a generated image.\n */\n mode: 'markdown' | 'html' | 'text' | 'react' | 'image'\n isComplete: boolean\n version?: number | null\n /** The answer that writes it. */\n messageExtId?: string\n /** The conversation it is written in (`new` until the server named it). */\n conversationId: string\n createdAt: string\n}\n\nlet artifacts: Record<string, ChatArtifact> = {}\n/** Document ids, most recently started last. */\nlet order: string[] = []\nconst listeners = new Set<() => void>()\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => listeners.delete(listener)\n}\n\nfunction emit() {\n listeners.forEach((listener) => listener())\n}\n\n/** Record an artifact event of a chat turn in `conversationId`. */\nexport function recordChatArtifact(event: ArtifactEvent, conversationId: string): void {\n const previous = artifacts[event.doc_ext_id]\n const artifact: ChatArtifact = {\n docExtId: event.doc_ext_id,\n title: event.title,\n content: event.content,\n // The backend schema lags the 'react' mode it also sends; the value passes through unchanged.\n mode: event.mode as ChatArtifact['mode'],\n isComplete: event.is_complete,\n version: event.version,\n createdAt: new Date().toISOString(),\n messageExtId: event.message_ext_id ?? undefined,\n conversationId,\n }\n artifacts = { ...artifacts, [artifact.docExtId]: artifact }\n if (!previous) order = [...order, artifact.docExtId]\n emit()\n}\n\n/** Forget every streamed artifact (sign-out). */\nexport function clearChatArtifacts(): void {\n if (order.length === 0) return\n artifacts = {}\n order = []\n emit()\n}\n\n/** Every artifact streamed in this tab, by document id. */\nexport function getChatArtifacts(): Readonly<Record<string, ChatArtifact>> {\n return artifacts\n}\n\n/** The artifact streaming (or streamed) into this document, if one did in this tab. */\nexport function getChatArtifact(documentId: string | null | undefined) {\n return documentId ? artifacts[documentId] : undefined\n}\n\n/** The artifact streaming into this document, if one is. Re-renders as it streams. */\nexport function useChatArtifact(documentId: string | null | undefined) {\n return useSyncExternalStore(\n subscribe,\n () => getChatArtifact(documentId),\n () => undefined\n )\n}\n\n/** The artifact this answer writes (or wrote), if it did in this tab. */\nexport function useMessageChatArtifact(messageId: string | null | undefined) {\n return useSyncExternalStore(\n subscribe,\n () =>\n messageId\n ? Object.values(artifacts).find((artifact) => artifact.messageExtId === messageId)\n : undefined,\n () => undefined\n )\n}\n"]}
@@ -1,5 +1,4 @@
1
- import { arbiMutationKeys, arbiQueryKeys } from './chunk-TK7ERJPE.js';
2
- import { useArbi } from './chunk-VGO77X5U.js';
1
+ import { arbiMutationKeys, arbiQueryKeys, useArbi } from './chunk-BFNY3RZG.js';
3
2
  import { create } from 'zustand';
4
3
  import { useRef, useCallback, useSyncExternalStore } from 'react';
5
4
  import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
@@ -570,14 +569,6 @@ function useDocument(docId, options) {
570
569
  refetchInterval: options?.pollWhileProcessing ? (query) => processingInterval(query.state.data) : false
571
570
  });
572
571
  }
573
- function useDocumentsById(docIds, options) {
574
- const arbi = useArbi();
575
- return useQuery({
576
- queryKey: arbiQueryKeys.documentsById(docIds),
577
- queryFn: () => arbi.documents.get(docIds),
578
- enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.isLoggedIn
579
- });
580
- }
581
572
  var SIMILARITY_THRESHOLD = 0.98;
582
573
  function useSimilarDocuments(options) {
583
574
  const arbi = useArbi();
@@ -648,6 +639,6 @@ function adjustTagCounts(qc, workspaceId, delta) {
648
639
  void invalidateTagTables(qc, workspaceId);
649
640
  }
650
641
 
651
- export { DISMISSED_TASK_TTL_MS, DOCUMENTS_FIRST_PAGE_MEASURE, DOCUMENTS_FIRST_PAGE_SIZE, DOCUMENTS_PAGE_SIZE, FINISHED_DOCUMENT_STATUSES, IN_FLIGHT_DOCUMENT_STATUSES, QUEUED_WRITE_BLOCKED_MESSAGE, QUEUED_WRITE_RETRY, SIMILARITY_THRESHOLD, adjustTagCounts, dropTagFromCachedDocuments, finishEntityExtraction, forgetDocuments, getCachedDocuments, inWorkspace, invalidateTagData, invalidateTagTables, isBlockedOnWorkspace, isDocumentsLoading, isRowNewer, isStaleTaskUpdate, isWorkspaceUnavailable, patchCachedDocument, patchDocuments, patchWorkspaceTags, primeOnArbi, primeOnClient, refreshDocuments, replayableTagMutations, resolveDocumentStatus, setCachedDocument, settledByRows, startEntityExtraction, stopDocumentsLoading, subscribeDocumentRows, upsertDocuments, useArbiWsStore, useCapturingWorkspace, useCreateTag, useDeleteTag, useDocument, useDocuments, useDocumentsById, useDocumentsLoading, useEntityExtractionDocIds, useExtractEntities, useInvalidateTagData, useIsCreatingTag, useRefreshDocuments, useSetTagValues, useSimilarDocuments, useTagKindSchema, useUpdateTag, useUpdateTagKindSchema };
652
- //# sourceMappingURL=chunk-VGAA7AFS.js.map
653
- //# sourceMappingURL=chunk-VGAA7AFS.js.map
642
+ export { DISMISSED_TASK_TTL_MS, DOCUMENTS_FIRST_PAGE_MEASURE, DOCUMENTS_FIRST_PAGE_SIZE, DOCUMENTS_PAGE_SIZE, FINISHED_DOCUMENT_STATUSES, IN_FLIGHT_DOCUMENT_STATUSES, QUEUED_WRITE_BLOCKED_MESSAGE, QUEUED_WRITE_RETRY, SIMILARITY_THRESHOLD, adjustTagCounts, dropTagFromCachedDocuments, finishEntityExtraction, forgetDocuments, getCachedDocuments, inWorkspace, invalidateTagData, invalidateTagTables, isBlockedOnWorkspace, isDocumentsLoading, isRowNewer, isStaleTaskUpdate, isWorkspaceUnavailable, patchCachedDocument, patchDocuments, patchWorkspaceTags, primeOnArbi, primeOnClient, refreshDocuments, replayableTagMutations, resolveDocumentStatus, setCachedDocument, settledByRows, startEntityExtraction, stopDocumentsLoading, subscribeDocumentRows, upsertDocuments, useArbiWsStore, useCapturingWorkspace, useCreateTag, useDeleteTag, useDocument, useDocuments, useDocumentsLoading, useEntityExtractionDocIds, useExtractEntities, useInvalidateTagData, useIsCreatingTag, useRefreshDocuments, useSetTagValues, useSimilarDocuments, useTagKindSchema, useUpdateTag, useUpdateTagKindSchema };
643
+ //# sourceMappingURL=chunk-S3OGDLDC.js.map
644
+ //# sourceMappingURL=chunk-S3OGDLDC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/documents/documents-cache.ts","../src/entity-extraction.ts","../src/queued-writes.ts","../src/tags.ts","../src/documents/documents-loader.ts","../src/documents/processing-order.ts","../src/websocket/store.ts","../src/documents/documents-data.ts"],"names":["update","useCallback","tagOps","controller","create","openWorkspaceId","useQueryClient","useQuery"],"mappings":"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","file":"chunk-S3OGDLDC.js","sourcesContent":["/**\n * The workspace documents list in the query cache: one entry per workspace\n * (`arbiQueryKeys.documents(workspaceId)`), read once (progressively, see `documents-loader.ts`)\n * and then kept current in place. Every write goes through {@link patchDocuments}, which also\n * tells row listeners (a grid that applies row transactions instead of re-diffing the whole list)\n * exactly which rows were added, changed or removed.\n *\n * A single document's own entry (`arbiQueryKeys.document(id)`, read by a viewer) is patched next to\n * the list by {@link setCachedDocument}, so a viewer never blanks while a write settles.\n */\n\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { components } from '@arbidocs/client'\nimport { arbiQueryKeys } from '../hooks'\n\n/** A document as the server lists it. */\nexport type WorkspaceDocument = components['schemas']['DocResponse']\n\n/** The rows one write added, changed and removed (removed: by id). */\nexport interface DocumentRowChange {\n workspaceId: string\n add: WorkspaceDocument[]\n update: WorkspaceDocument[]\n remove: string[]\n}\n\ntype RowListener = (change: DocumentRowChange) => void\n\nconst rowListeners = new Set<RowListener>()\n\n/**\n * Follow the row-level changes of every write to a workspace documents list (a grid applying them\n * as transactions). Returns the unsubscribe.\n */\nexport function subscribeDocumentRows(listener: RowListener): () => void {\n rowListeners.add(listener)\n return () => {\n rowListeners.delete(listener)\n }\n}\n\n/** The cached documents of a workspace (`undefined` before its list has been read). */\nexport function getCachedDocuments(\n qc: QueryClient,\n workspaceId: string | null | undefined\n): WorkspaceDocument[] | undefined {\n if (!workspaceId) return undefined\n return qc.getQueryData<WorkspaceDocument[]>(arbiQueryKeys.documents(workspaceId))\n}\n\n/** Every cached workspace documents list, with its workspace. */\nfunction cachedLists(qc: QueryClient): Array<[string, WorkspaceDocument[]]> {\n return qc\n .getQueriesData<WorkspaceDocument[]>({ queryKey: arbiQueryKeys.allDocuments() })\n .flatMap(([key, data]) =>\n typeof key[2] === 'string' && Array.isArray(data) ? [[key[2], data]] : []\n )\n}\n\n/** Diff two versions of a list by id. */\nfunction diffRows(\n workspaceId: string,\n before: WorkspaceDocument[],\n after: WorkspaceDocument[]\n): DocumentRowChange {\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n const add: WorkspaceDocument[] = []\n const update: WorkspaceDocument[] = []\n const seen = new Set<string>()\n for (const doc of after) {\n seen.add(doc.external_id)\n const previous = beforeById.get(doc.external_id)\n if (!previous) add.push(doc)\n else if (previous !== doc) update.push(doc)\n }\n const remove = [...beforeById.keys()].filter((id) => !seen.has(id))\n return { workspaceId, add, update, remove }\n}\n\n/**\n * Apply `reducer` to a workspace's documents list, or (no `workspaceId`) to every cached one: the\n * one place a list is written after it was read. Returning the same array is a no-op. Row\n * listeners get the diff; a document that moved to a new version makes the open version lists\n * re-read. A workspace whose list has not been read is left alone (its first read brings it).\n */\nexport function patchDocuments(\n qc: QueryClient,\n reducer: (documents: WorkspaceDocument[]) => WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n const lists: Array<[string, WorkspaceDocument[]]> = workspaceId\n ? (() => {\n const current = getCachedDocuments(qc, workspaceId)\n return current ? [[workspaceId, current] as [string, WorkspaceDocument[]]] : []\n })()\n : cachedLists(qc)\n for (const [id, before] of lists) {\n const after = reducer(before)\n if (after === before) continue\n qc.setQueryData(arbiQueryKeys.documents(id), after)\n const change = diffRows(id, before, after)\n const beforeById = new Map(before.map((doc) => [doc.external_id, doc]))\n if (\n change.update.some(\n (doc) => doc.current_version !== beforeById.get(doc.external_id)?.current_version\n )\n )\n void qc.invalidateQueries({ queryKey: arbiQueryKeys.allDocumentVersions() })\n if (change.add.length || change.update.length || change.remove.length)\n for (const listener of rowListeners) listener(change)\n }\n}\n\n/** Put `doc` in its list in place, or at the end when the list does not hold it yet. */\nexport function upsertDocuments(\n qc: QueryClient,\n documents: WorkspaceDocument[],\n workspaceId?: string | null\n): void {\n if (!documents.length) return\n const byId = new Map(documents.map((doc) => [doc.external_id, doc]))\n const byWorkspace = new Map<string, WorkspaceDocument[]>()\n for (const doc of documents) {\n const ws = workspaceId ?? doc.workspace_ext_id\n byWorkspace.set(ws, [...(byWorkspace.get(ws) ?? []), doc])\n }\n for (const [ws, incoming] of byWorkspace) {\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n return [\n ...old.map((doc) => byId.get(doc.external_id) ?? doc),\n ...incoming.filter((doc) => !known.has(doc.external_id)),\n ]\n },\n ws\n )\n }\n}\n\n/** Write a document's own entry (what `useDocument` reads), keeping a viewer current. */\nexport function setCachedDocument(qc: QueryClient, doc: WorkspaceDocument): void {\n qc.setQueryData(arbiQueryKeys.document(doc.external_id), doc)\n}\n\n/** Apply `reducer` to a document's own entry, when one is cached. */\nexport function patchCachedDocument(\n qc: QueryClient,\n docId: string,\n reducer: (doc: WorkspaceDocument) => WorkspaceDocument\n): void {\n const current = qc.getQueryData<WorkspaceDocument | null>(arbiQueryKeys.document(docId))\n if (current) qc.setQueryData(arbiQueryKeys.document(docId), reducer(current))\n}\n\n/** A deleted tag leaves every cached document that carried it: the lists' rows and their entries. */\nexport function dropTagFromCachedDocuments(qc: QueryClient, tagId: string): void {\n const strip = (doc: WorkspaceDocument): WorkspaceDocument => {\n const doctags = doc.doctags?.filter((dt) => dt.tag_ext_id !== tagId)\n return doctags && doctags.length !== doc.doctags?.length ? { ...doc, doctags } : doc\n }\n const carriers: string[] = []\n patchDocuments(qc, (docs) => {\n const next = docs.map(strip)\n next.forEach((doc, i) => doc !== docs[i] && carriers.push(doc.external_id))\n return carriers.length ? next : docs\n })\n for (const id of carriers) patchCachedDocument(qc, id, strip)\n}\n\n/** Forget everything cached about deleted documents, so nothing re-reads them into a 404. */\nexport function forgetDocuments(qc: QueryClient, docIds: string[]): void {\n for (const id of docIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.document(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.documentVersions(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.parsedDocument(id) })\n }\n}\n","/**\n * The documents whose people and organisations are being found (`useExtractEntities`), from the\n * request until the live connection says the batch is done (`batch_complete`, `entity_extract`):\n * the package's WebSocket (`ArbiWebSocketProvider`) ends it, and a host on its own connection calls\n * `finishEntityExtraction` from its handler.\n */\n\nimport { create } from 'zustand'\n\nconst useEntityExtractionStore = create<{ docIds: readonly string[] }>(() => ({ docIds: [] }))\n\nfunction update(docIds: readonly string[], running: boolean): void {\n if (!docIds.length) return\n useEntityExtractionStore.setState((state) => {\n const ids = new Set(state.docIds)\n docIds.forEach((id) => (running ? ids.add(id) : ids.delete(id)))\n return { docIds: [...ids] }\n })\n}\n\n/** The documents an extraction was started on are running. */\nexport function startEntityExtraction(docIds: readonly string[]): void {\n update(docIds, true)\n}\n\n/** The extraction of these documents is done. */\nexport function finishEntityExtraction(docIds: readonly string[]): void {\n update(docIds, false)\n}\n\n/** The documents being extracted now. */\nexport function useEntityExtractionDocIds(): readonly string[] {\n return useEntityExtractionStore((state) => state.docIds)\n}\n","/**\n * The workspace of a write that may be queued (offline, then replayed on reconnect or after a\n * reload). The workspace is captured when the write is made and kept with it, and the write is\n * sent in that workspace: it is opened for this session first (its key deposited, without\n * switching to it), and the request names it or acts on resources the server keys by their own\n * workspace. So a replay never lands in whatever workspace happens to be open by then.\n *\n * When the workspace cannot be opened (signed out, access removed), nothing is sent: the write\n * fails with `ArbiWorkspaceUnavailableError`, is retried a few times (a reload replays before the\n * sign-in has finished), and then stays in the pending changes as not sent, with its local edit\n * kept, rather than going anywhere else.\n */\n\nimport { useCallback, useRef } from 'react'\nimport { isAbortError, type ArbiClient } from '@arbidocs/client'\nimport { ArbiWorkspaceUnavailableError } from '@arbidocs/sdk/browser'\n\n/** A queued write's own workspace (`wrk-…`), captured when it was made. */\nexport interface QueuedWriteWorkspace {\n /** The workspace the write belongs to. Filled in when it is made; absent on older queued writes. */\n workspaceId?: string\n}\n\n/** What a write that could not be sent in its workspace says. */\nexport const QUEUED_WRITE_BLOCKED_MESSAGE =\n \"This change belongs to a workspace that can't be opened right now, so it was not sent. It is kept here until it can be.\"\n\n/** Opens a workspace for this server session without switching to it (nothing for the current one). */\nexport type WorkspacePrimer = (workspaceId: string) => Promise<void> | void\n\n/** {@link WorkspacePrimer} on a bare client (a replay after a reload): its key, via `/prime-key`. */\nexport function primeOnClient(client: ArbiClient): WorkspacePrimer {\n return (workspaceId) =>\n workspaceId === client.session.getState().selectedWorkspaceId\n ? undefined\n : client.workspaceKeys.prime(workspaceId)\n}\n\n/** {@link WorkspacePrimer} on an `Arbi` (`workspaces.open`, which never switches). */\nexport function primeOnArbi(arbi: {\n hasWorkspace: boolean\n getWorkspaceId(): string\n workspaces: { open(workspaceId: string): Promise<void> }\n}): WorkspacePrimer {\n return (workspaceId) =>\n arbi.hasWorkspace && workspaceId === arbi.getWorkspaceId()\n ? undefined\n : arbi.workspaces.open(workspaceId)\n}\n\n/**\n * Run `write` in `workspaceId`: that workspace is opened for this server session first (`prime`).\n * When it can't be, nothing is sent. No workspace (a write queued before workspaces were\n * recorded): as before.\n */\nexport async function inWorkspace<T>(\n prime: WorkspacePrimer,\n workspaceId: string | null | undefined,\n write: () => Promise<T>\n): Promise<T> {\n if (workspaceId) {\n try {\n await prime(workspaceId)\n } catch (error) {\n if (isAbortError(error)) throw error\n throw new ArbiWorkspaceUnavailableError(workspaceId, error, QUEUED_WRITE_BLOCKED_MESSAGE)\n }\n }\n return write()\n}\n\n/** Whether a write failed only because its workspace could not be opened (nothing was sent). */\nexport function isWorkspaceUnavailable(error: unknown): boolean {\n return error instanceof ArbiWorkspaceUnavailableError\n}\n\n/** How many times a write whose workspace cannot be opened is tried again, and how long apart. */\nexport const QUEUED_WRITE_RETRY = {\n retry: (failureCount: number, error: unknown) =>\n isWorkspaceUnavailable(error) && failureCount < 8,\n retryDelay: (attempt: number) => Math.min(1000 * 2 ** attempt, 30_000),\n} as const\n\n/** Whether a queued write is held back because its workspace cannot be opened. */\nexport function isBlockedOnWorkspace(mutation: {\n state: { error?: unknown; failureReason?: unknown }\n}): boolean {\n return isWorkspaceUnavailable(mutation.state.error ?? mutation.state.failureReason)\n}\n\n/**\n * Fill in the workspace of each write a mutation makes, when its caller gave none: `mutate` and\n * `mutateAsync` pass `capture(variables)` on. Read when the write is made, so a write queued\n * offline keeps the workspace it was made in. The wrapped functions are as stable as the mutation's.\n */\nexport function useCapturingWorkspace<\n V,\n T extends { mutate: (variables: V, ...rest: never[]) => unknown; mutateAsync: unknown },\n>(mutation: T, capture: (variables: V) => V): T {\n const captureRef = useRef(capture)\n captureRef.current = capture\n const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation\n const mutate = useCallback(\n (variables: V, ...rest: never[]) =>\n (rawMutate as (v: V, ...r: never[]) => unknown)(captureRef.current(variables), ...rest),\n [rawMutate]\n ) as T['mutate']\n const mutateAsync = useCallback(\n (variables: V, ...rest: never[]) =>\n (rawMutateAsync as (v: V, ...r: never[]) => Promise<unknown>)(\n captureRef.current(variables),\n ...rest\n ),\n [rawMutateAsync]\n ) as T['mutateAsync']\n return { ...mutation, mutate, mutateAsync }\n}\n","/**\n * Tags: the open workspace's tag list (`useTags()`), the writes (create, update, delete, values,\n * entity extraction), and tag kinds — a kind's fields in the workspace are the columns of a table\n * of its tags (`useTagKindSchema('issue')`), whose rows are the tag list filtered by kind with\n * links (`useTags(workspaceId, { kind, include })`).\n *\n * Everything is cached under the workspace's tags (`arbiQueryKeys.tags`). The whole list is kept\n * current in place: every write here patches it ({@link patchWorkspaceTags}, which a host also\n * uses for its own writes that move a tag's counts, e.g. applying it to documents) and refreshes\n * the filtered lists (the tables). Anything that invalidates the workspace's tags (a document batch\n * finishing, {@link useInvalidateTagData} after a doctag or fact change) refreshes them all.\n *\n * Creating a tag can be queued while offline and replayed after a reload: see `offline.ts`.\n *\n * Requires an `ArbiHost` (with an `arbi`) and a React Query client above it.\n */\n\nimport { useCallback } from 'react'\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { ArbiClient } from '@arbidocs/client'\nimport {\n tags as tagOps,\n type TagChange,\n type TagFieldDefinition,\n type TagKind,\n type TagKindSchema,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport { dropTagFromCachedDocuments } from './documents/documents-cache'\nimport { startEntityExtraction } from './entity-extraction'\nimport { arbiMutationKeys, arbiQueryKeys } from './hooks'\nimport {\n QUEUED_WRITE_RETRY,\n inWorkspace,\n primeOnArbi,\n primeOnClient,\n useCapturingWorkspace,\n} from './queued-writes'\n\n/** The workspace open on `arbi`, or `null` (`getWorkspaceId()` throws when none is open). */\n/** The workspace whose cached tag list holds `tagId`, if any. */\nfunction workspaceOfTag(qc: QueryClient, tagId: string): string | null {\n for (const [key, tags] of qc.getQueriesData<TagResponse[]>({\n queryKey: arbiQueryKeys.allTags(),\n })) {\n if (Array.isArray(tags) && tags.some((t) => t.external_id === tagId))\n return (key[2] as string | undefined) ?? null\n }\n return null\n}\n\nfunction openWorkspaceId(arbi: ReturnType<typeof useArbi>): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * Apply `reducer` to a workspace's cached tag list (nothing cached: nothing to do). The list is\n * read once, then kept current by these patches; a host's own write that changes a tag (applying\n * it to documents moves its `doctag_count`) patches it here too.\n */\nexport function patchWorkspaceTags(\n qc: QueryClient,\n workspaceId: string,\n reducer: (tags: TagResponse[]) => TagResponse[]\n): void {\n const key = arbiQueryKeys.tags(workspaceId)\n const current = qc.getQueryData<TagResponse[]>(key)\n if (!current) return\n const next = reducer(current)\n if (next !== current) qc.setQueryData(key, next)\n}\n\n/** Refetch a workspace's tables of tags (its filtered lists), not the whole list. */\nexport function invalidateTagTables(qc: QueryClient, workspaceId: string): Promise<void> {\n return qc.invalidateQueries({ queryKey: arbiQueryKeys.tagLists(workspaceId) })\n}\n\n/** Refresh what a tag, doctag or fact change affects: the workspace's tags, tables and facts. */\nexport function invalidateTagData(qc: QueryClient, workspaceId: string): Promise<unknown> {\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.tags(workspaceId) }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n}\n\n/** {@link invalidateTagData} for the open workspace: call it after a doctag or fact write. */\nexport function useInvalidateTagData(): () => Promise<unknown> {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useCallback(() => {\n const workspaceId = openWorkspaceId(arbi)\n return workspaceId ? invalidateTagData(qc, workspaceId) : Promise.resolve()\n }, [arbi, qc])\n}\n\n/**\n * What a new tag is: its name, and optionally kind, format, parent, values, sharing, and the workspace it goes in\n * (absent: the open one).\n */\nexport type CreateTagInput = Parameters<typeof tagOps.createTag>[1]\n\n/** A created tag joins its workspace's list; the tables re-read. */\nfunction settleCreatedTag(qc: QueryClient, created: TagResponse): Promise<void> {\n const workspaceId = created.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.some((t) => t.external_id === created.external_id) ? old : [...old, created]\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/** A changed tag replaces its entry in the list; the tables re-read. */\nfunction settleChangedTag(qc: QueryClient, tag: TagResponse): Promise<void> {\n const workspaceId = tag.workspace_ext_id\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old.map((t) => (t.external_id === tag.external_id ? { ...t, ...tag } : t))\n )\n return invalidateTagTables(qc, workspaceId)\n}\n\n/**\n * The tag writes a host may queue while offline and replay after a reload (`offline.ts`): each\n * key's request on a bare client, and what its success does to the cache.\n */\nexport const replayableTagMutations = [\n {\n mutationKey: arbiMutationKeys.createTag(),\n // In the workspace it was made in (named on the request), opened for this session first.\n run: (client: ArbiClient, input: CreateTagInput) =>\n inWorkspace(primeOnClient(client), input.workspaceId, () => tagOps.createTag(client, input)),\n settle: (qc: QueryClient, created: TagResponse) => settleCreatedTag(qc, created),\n },\n] as const\n\n/**\n * Create a tag in the open workspace, or `workspaceId` (`{ name, kind: 'issue' }`, `{ name, parentId }`, …): it is\n * added to the tag list and the tables re-read. Resolves with the new tag. Offline it is held and\n * sent on reconnect (a host that registers `registerArbiMutationDefaults` keeps it across reloads).\n */\nexport function useCreateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n // The workspace is captured when the tag is made, so a create queued offline keeps it.\n const capture = (input: CreateTagInput): CreateTagInput =>\n input.workspaceId || !arbi.hasWorkspace\n ? input\n : { ...input, workspaceId: arbi.getWorkspaceId() }\n return useCapturingWorkspace(\n useMutation({\n mutationKey: arbiMutationKeys.createTag(),\n mutationFn: (input: CreateTagInput): Promise<TagResponse> =>\n inWorkspace(primeOnArbi(arbi), input.workspaceId, () => arbi.tags.create(input)),\n onSuccess: (created) => settleCreatedTag(qc, created),\n ...QUEUED_WRITE_RETRY,\n }),\n capture\n )\n}\n\n/**\n * Whether a tag of this name (any case) is being created right now: a second create of the same\n * name (a double Enter) is skipped instead of making a duplicate.\n */\nexport function useIsCreatingTag(): (name: string) => boolean {\n const qc = useQueryClient()\n return useCallback(\n (name: string) => {\n const wanted = name.trim().toLowerCase()\n return (\n qc.getMutationCache().findAll({\n mutationKey: arbiMutationKeys.createTag(),\n predicate: (m) =>\n m.state.status === 'pending' &&\n (m.state.variables as CreateTagInput | undefined)?.name.trim().toLowerCase() === wanted,\n }).length > 0\n )\n },\n [qc]\n )\n}\n\n/** Change a tag (name, format, instruction, parent, sharing, values): patched in the list. */\nexport function useUpdateTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({ tagId, change }: { tagId: string; change: TagChange }): Promise<TagResponse> =>\n arbi.tags.update(tagId, change),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/** Merge-patch a tag's values for its kind's fields (`null` clears one); its tables refresh. */\nexport function useSetTagValues() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTag(),\n mutationFn: ({\n tagId,\n values,\n }: {\n tagId: string\n values: Record<string, unknown>\n }): Promise<TagResponse> => arbi.tags.setValues(tagId, values),\n onSuccess: (tag) => settleChangedTag(qc, tag),\n })\n}\n\n/**\n * Delete a tag: it leaves the list (its sub-tags move to the top level on the server, so the list\n * re-reads them), and the tables and facts re-read. A host that shows the tag on its own items\n * (documents' tags) follows `arbiMutationKeys.deleteTag()` to drop it there.\n */\nexport function useDeleteTag() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.deleteTag(),\n mutationFn: (tagId: string) => arbi.tags.delete(tagId),\n // The tag's own workspace (the cached list holding it), else the one open when it is sent: a\n // switch while the delete runs must not patch the next workspace's list.\n onMutate: (tagId) => ({ workspaceId: workspaceOfTag(qc, tagId) ?? openWorkspaceId(arbi) }),\n onSuccess: (_data, tagId, context) => {\n // Its pills come off the documents grid in place (and off any open document).\n dropTagFromCachedDocuments(qc, tagId)\n const workspaceId = context?.workspaceId\n if (!workspaceId) return\n patchWorkspaceTags(qc, workspaceId, (old) =>\n old\n .filter((t) => t.external_id !== tagId)\n .map((t) => (t.parent_ext_id === tagId ? { ...t, parent_ext_id: null } : t))\n )\n return Promise.all([\n invalidateTagTables(qc, workspaceId),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.facts(workspaceId) }),\n ])\n },\n })\n}\n\n/**\n * Find the people and organisations documents name and link each to its entity tag. Accepted at\n * once with the documents' ids, which show as running (`useEntityExtractionDocIds`) until a\n * `batch_complete` (`entity_extract`) WebSocket message says they are done.\n */\nexport function useExtractEntities() {\n const arbi = useArbi()\n return useMutation({\n mutationKey: arbiMutationKeys.extractEntities(),\n mutationFn: (docIds: string[]) => arbi.tags.extractEntities(docIds),\n onSuccess: (data) => startEntityExtraction(data.doc_ext_ids),\n })\n}\n\n/**\n * A kind's fields in the open workspace (`'issue'`: its issue fields): the columns of a table of\n * that kind's tags. The built-in ones (`is_default`) until the workspace sets its own.\n */\nexport function useTagKindSchema(\n kind: TagKind | null | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const workspaceId = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.tagKind(workspaceId, kind ?? ''),\n queryFn: (): Promise<TagKindSchema> =>\n arbi.readInWorkspace(workspaceId, () => arbi.tagKinds.get(kind as TagKind)),\n enabled: (options?.enabled ?? true) && !!kind && !!workspaceId,\n })\n}\n\n/**\n * Set a kind's fields in full (a field with its `id` keeps its values; one without is new; one\n * left out is removed). The kind's schema and the workspace's tags refresh.\n */\nexport function useUpdateTagKindSchema() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation({\n mutationKey: arbiMutationKeys.updateTagKindSchema(),\n mutationFn: ({\n kind,\n fields,\n }: {\n kind: TagKind\n fields: TagFieldDefinition[]\n }): Promise<TagKindSchema> => arbi.tagKinds.update(kind, fields),\n // The workspace open when it is sent (the server writes the open workspace's schema until\n // the request can name it): a switch meanwhile must not rewrite the next workspace's columns.\n onMutate: () => ({ workspaceId: openWorkspaceId(arbi) }),\n onSuccess: (schema, _input, context) => {\n const workspaceId = context?.workspaceId\n if (!workspaceId) return\n qc.setQueryData(arbiQueryKeys.tagKind(workspaceId, schema.kind), schema)\n return invalidateTagData(qc, workspaceId)\n },\n })\n}\n","/**\n * Reading a workspace's documents progressively: the first page is the query's result, so the\n * list shows within a few hundred milliseconds even for 100k documents, and the remaining pages\n * are appended to the same cache entry in the background as they arrive. One background read per\n * workspace; opening another workspace stops the previous one. Whether a background read is\n * running is observable ({@link useDocumentsLoading}), for a \"still loading\" indicator.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { patchDocuments, type WorkspaceDocument } from './documents-cache'\n\n/** First page: small, so rows are on screen in a few hundred ms even in a large workspace. */\nexport const DOCUMENTS_FIRST_PAGE_SIZE = 500\n\n/** Later pages: larger, fewer round trips (the server caps a page at 10 000). */\nexport const DOCUMENTS_PAGE_SIZE = 2000\n\n/**\n * The time to the first page, as a `performance` measure of this name (a host reporting\n * performance can observe it).\n */\nexport const DOCUMENTS_FIRST_PAGE_MEASURE = 'arbi:document-list:page1'\nconst FIRST_PAGE_MEASURE = DOCUMENTS_FIRST_PAGE_MEASURE\nconst FIRST_PAGE_START = 'arbi:document-list:start'\n\nfunction mark(name: string): void {\n try {\n performance.mark(name)\n } catch {\n // No performance timeline here (an old runtime, a test): nothing to record.\n }\n}\n\nfunction measure(name: string, start: string): void {\n try {\n performance.measure(name, start)\n } catch {\n // The start mark is missing: nothing to record.\n }\n}\n\nconst backgroundReads = new Map<string, AbortController>()\nconst loadingListeners = new Set<() => void>()\n\nfunction emitLoading(): void {\n for (const listener of loadingListeners) listener()\n}\n\nfunction subscribeLoading(listener: () => void): () => void {\n loadingListeners.add(listener)\n return () => {\n loadingListeners.delete(listener)\n }\n}\n\n/** Whether a workspace's remaining document pages are being read in the background. */\nexport function isDocumentsLoading(): boolean {\n return backgroundReads.size > 0\n}\n\n/** True while the remaining pages of a documents list are still arriving. */\nexport function useDocumentsLoading(): boolean {\n return useSyncExternalStore(subscribeLoading, isDocumentsLoading, () => false)\n}\n\n/** Stop a workspace's background read (closing the workspace). */\nexport function stopDocumentsLoading(workspaceId: string): void {\n const controller = backgroundReads.get(workspaceId)\n if (!controller) return\n controller.abort()\n backgroundReads.delete(workspaceId)\n emitLoading()\n}\n\n/**\n * Read a workspace's documents: resolves with the first page and appends the rest to\n * `arbiQueryKeys.documents(workspaceId)` in the background. The query function of `useDocuments`.\n */\nexport async function loadDocuments(\n qc: QueryClient,\n arbi: Arbi,\n workspaceId: string,\n signal?: AbortSignal\n): Promise<WorkspaceDocument[]> {\n let stopped = false\n for (const [id, controller] of backgroundReads) {\n if (id === workspaceId) continue\n controller.abort()\n backgroundReads.delete(id)\n stopped = true\n }\n if (stopped) emitLoading()\n\n const controller = new AbortController()\n signal?.addEventListener('abort', () => controller.abort(), { once: true })\n // Named, not the session's open workspace: the pages are this workspace's whatever the server\n // session is in, so a list read across a workspace switch can never be another's.\n const pages = arbi.documents.listPaginated({\n workspaceId,\n pageSize: DOCUMENTS_PAGE_SIZE,\n firstPageSize: DOCUMENTS_FIRST_PAGE_SIZE,\n signal: controller.signal,\n })\n mark(FIRST_PAGE_START)\n const first = await pages.next()\n const firstPage = first.done ? [] : first.value\n measure(FIRST_PAGE_MEASURE, FIRST_PAGE_START)\n if (first.done || firstPage.length < DOCUMENTS_FIRST_PAGE_SIZE) return firstPage\n if (backgroundReads.has(workspaceId)) {\n controller.abort()\n return firstPage\n }\n\n backgroundReads.set(workspaceId, controller)\n emitLoading()\n void appendRemainingPages(qc, workspaceId, pages, controller.signal).finally(() => {\n if (backgroundReads.get(workspaceId) !== controller) return\n backgroundReads.delete(workspaceId)\n emitLoading()\n })\n return firstPage\n}\n\nasync function appendRemainingPages(\n qc: QueryClient,\n workspaceId: string,\n pages: AsyncGenerator<WorkspaceDocument[]>,\n signal: AbortSignal\n): Promise<void> {\n // Let the query store the first page before the second is appended to it.\n await Promise.resolve()\n try {\n for await (const page of pages) {\n if (signal.aborted) return\n // A write may already have added some of these (an upload finishing meanwhile).\n patchDocuments(\n qc,\n (old) => {\n const known = new Set(old.map((doc) => doc.external_id))\n const fresh = page.filter((doc) => !known.has(doc.external_id))\n return fresh.length ? [...old, ...fresh] : old\n },\n workspaceId\n )\n }\n } catch (error) {\n if (!signal.aborted) console.error(`Reading the documents of ${workspaceId} failed:`, error)\n }\n}\n\n/** Test-only: stop every background read. @internal */\nexport function resetDocumentsLoadingForTests(): void {\n for (const controller of backgroundReads.values()) controller.abort()\n backgroundReads.clear()\n emitLoading()\n}\n","/**\n * Which is newer: a document's live processing status or its row as last read?\n *\n * Every `task_update` carries `seq`, taken by the server from one sequence for all documents and\n * all of its instances, so a higher seq is a later event however the events arrive. A document row\n * carries `status_seq`: the seq of the last time its processing ended (a finished status written or\n * broadcast). The two compare:\n * - an event at or below the seq of the one already held is stale (overtaken), and is dropped;\n * - a row whose `status_seq` is above the live status's seq finished after it: the live status is\n * over (its final event was lost), and the row wins;\n * - a live status above the row's `status_seq` is newer than the row: the document is being\n * processed again (AI fields being filled) although the row still says it finished.\n *\n * Without the seqs (an optimistic \"queued\" set here, a server before them) the older rule stands:\n * a live in-flight status wins, then a finished row, then whatever was heard live.\n */\n\n/** Statuses after which a document's processing is over (`low-content`: indexed, little text). */\nexport const FINISHED_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'completed',\n 'low-content',\n 'failed',\n 'skipped',\n 'empty',\n])\n\n/** A live processing status and its order (`task_update.seq`). */\nexport interface SequencedTask {\n status: string\n seq?: number | null\n}\n\n/** A document row's status and the order of its last finished status (`status_seq`). */\nexport interface SequencedRow {\n status?: string | null\n status_seq?: number | null\n}\n\n/** Statuses of a document still being processed. */\nexport const IN_FLIGHT_DOCUMENT_STATUSES: ReadonlySet<string> = new Set([\n 'uploading',\n 'queued',\n 'parsing',\n 'encrypting',\n 'indexing',\n 'analysing',\n])\n\nfunction ordered(value: number | null | undefined): value is number {\n return typeof value === 'number'\n}\n\n/** Whether `next` is older than (or the same event as) the live status already held. */\nexport function isStaleTaskUpdate(held: SequencedTask | undefined, next: SequencedTask): boolean {\n return !!held && ordered(held.seq) && ordered(next.seq) && next.seq <= held.seq\n}\n\n/**\n * Whether the row is newer than the live status: `true` / `false` when both are ordered, `undefined`\n * when they cannot be compared.\n */\nexport function isRowNewer(row: SequencedRow, task: SequencedTask): boolean | undefined {\n if (!ordered(row.status_seq) || !ordered(task.seq)) return undefined\n return row.status_seq > task.seq\n}\n\n/** The status a document shows now: its row's, or the live one when that is newer. */\nexport function resolveDocumentStatus(row: SequencedRow, task: SequencedTask | undefined): string {\n const rowStatus = (row.status ?? '').toLowerCase()\n const live = task?.status\n if (!task || !live) return rowStatus\n const rowNewer = isRowNewer(row, task)\n if (rowNewer !== undefined) return rowNewer ? rowStatus || live : live\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(live)) return live\n if (FINISHED_DOCUMENT_STATUSES.has(rowStatus)) return rowStatus\n return live\n}\n\n/**\n * The live statuses a read of `rows` ends: each in-flight one whose row has since finished. Ordered,\n * the row must be newer (so a reprocess the row predates keeps its progress); unordered, a finished\n * row is enough (the older rule). Returns each such task with the row's status and order. Cheap when\n * nothing is in flight (it runs on every read of a list).\n */\nexport function settledByRows<T extends SequencedTask & { doc_ext_id: string }>(\n tasks: Readonly<Record<string, T>>,\n rows: ReadonlyArray<SequencedRow & { external_id: string }>\n): T[] {\n const inFlight = new Map<string, T>()\n for (const task of Object.values(tasks))\n if (IN_FLIGHT_DOCUMENT_STATUSES.has(task.status)) inFlight.set(task.doc_ext_id, task)\n if (!inFlight.size) return []\n const settled: T[] = []\n for (const row of rows) {\n const task = inFlight.get(row.external_id)\n if (!task) continue\n const rowStatus = (row.status ?? '').toLowerCase()\n if (!FINISHED_DOCUMENT_STATUSES.has(rowStatus) || isRowNewer(row, task) === false) continue\n settled.push({ ...task, status: rowStatus, seq: row.status_seq ?? task.seq })\n }\n return settled\n}\n","/**\n * Canonical WebSocket state, shared across apps.\n *\n * One store for every site's live connection: its status, people's presence and each document's\n * live processing. `ArbiWebSocketProvider` feeds it; components read it with the selector hooks in\n * `./hooks` and the documents hooks (`useProcessingTasks`, `useWorkspaceProcessing`).\n */\n\nimport { create } from 'zustand'\nimport type { WsTaskUpdateMessage, WsPresenceUpdateMessage } from '@arbidocs/client'\nimport {\n FINISHED_DOCUMENT_STATUSES,\n isStaleTaskUpdate,\n settledByRows,\n type SequencedRow,\n} from '../documents/processing-order'\n\n/** `error`: the host's socket failed. */\nexport type ArbiWsStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'\n\n/**\n * A document's live processing: its last `task_update` (or a status set here, such as \"queued\"\n * while a write sends it back into processing), with when it was first seen (`startTime`) and\n * when it finished (`endTime`), both on this device's clock.\n */\nexport type LiveTask = Omit<WsTaskUpdateMessage, 'type' | 'seq'> & {\n type?: 'task_update'\n seq?: number | null\n startTime?: number\n endTime?: number\n}\n\n/** How long a document's tasks stay dismissed (late updates of a deleted upload are dropped). */\nexport const DISMISSED_TASK_TTL_MS = 10 * 60 * 1000\n\nexport interface ArbiWsState {\n /** Live connection status of the shared socket. */\n status: ArbiWsStatus\n /** Latest processing status per document id (the `task_update` stream). */\n tasks: Record<string, LiveTask>\n /** Documents whose processing rows were dismissed (deleted, cleared), with when. */\n dismissed: Record<string, number>\n /** The most recent `task_update` — a convenient single-value change trigger. */\n lastTaskUpdate: WsTaskUpdateMessage | null\n /** Online status keyed by user id (the `presence_update` stream). */\n presence: Record<string, string>\n /**\n * The server closed this socket for a newer session of the same user (another device, close\n * code 1008). The socket stays closed: reconnecting would only be evicted again.\n */\n evicted: boolean\n setStatus: (status: ArbiWsStatus) => void\n setEvicted: (evicted: boolean) => void\n /**\n * Take a `task_update`, unless it is older than the one held for its document (`seq`) or the\n * document was dismissed a moment ago. Resolves whether it was taken.\n */\n applyTaskUpdate: (msg: WsTaskUpdateMessage) => boolean\n /** Set a document's live processing directly (an optimistic status, or an undo). */\n putTask: (task: LiveTask) => void\n /** Drop a document's processing row, and ignore its late updates for a while. */\n clearTask: (docId: string) => void\n /** Drop every finished processing row (the in-flight ones stay). */\n clearFinishedTasks: () => void\n /** End the in-flight statuses that documents read since say finished after them. */\n settleTasks: (rows: ReadonlyArray<SequencedRow & { external_id: string }>) => void\n applyPresence: (msg: WsPresenceUpdateMessage) => void\n reset: () => void\n}\n\nconst finished = (status: string) => FINISHED_DOCUMENT_STATUSES.has(status)\n\nexport const useArbiWsStore = create<ArbiWsState>((set, get) => ({\n status: 'disconnected',\n tasks: {},\n dismissed: {},\n lastTaskUpdate: null,\n presence: {},\n evicted: false,\n setStatus: (status) => set({ status }),\n setEvicted: (evicted) => set({ evicted }),\n applyTaskUpdate: (msg) => {\n const { tasks, dismissed } = get()\n const dismissedAt = dismissed[msg.doc_ext_id]\n if (dismissedAt !== undefined && Date.now() - dismissedAt < DISMISSED_TASK_TTL_MS) return false\n const held = tasks[msg.doc_ext_id]\n if (isStaleTaskUpdate(held, msg)) return false\n const now = Date.now()\n const task: LiveTask = {\n ...msg,\n startTime: held?.startTime ?? now,\n endTime: finished(msg.status) ? (held?.endTime ?? now) : undefined,\n }\n set({ tasks: { ...tasks, [msg.doc_ext_id]: task }, lastTaskUpdate: msg })\n return true\n },\n putTask: (task) => set((s) => ({ tasks: { ...s.tasks, [task.doc_ext_id]: task } })),\n clearTask: (docId) =>\n set((s) => {\n const tasks = { ...s.tasks }\n delete tasks[docId]\n return { tasks, dismissed: { ...s.dismissed, [docId]: Date.now() } }\n }),\n clearFinishedTasks: () =>\n set((s) => ({\n tasks: Object.fromEntries(Object.entries(s.tasks).filter(([, t]) => !finished(t.status))),\n })),\n settleTasks: (rows) =>\n set((s) => {\n const settled = settledByRows(s.tasks, rows)\n if (!settled.length) return s\n const tasks = { ...s.tasks }\n const now = Date.now()\n for (const task of settled)\n tasks[task.doc_ext_id] = { ...(task as LiveTask), endTime: task.endTime ?? now }\n return { tasks }\n }),\n applyPresence: (msg) => set((s) => ({ presence: { ...s.presence, [msg.user_id]: msg.status } })),\n reset: () =>\n set({ status: 'disconnected', tasks: {}, dismissed: {}, lastTaskUpdate: null, presence: {} }),\n}))\n","/**\n * Reading documents: a workspace's list (`useDocuments`, progressive, read once and then patched in\n * place), one document (`useDocument`, for a viewer), a set of documents by id, near-duplicate pairs\n * (`useSimilarDocuments`), and {@link refreshDocuments}, which re-reads just the documents an event\n * named and patches them into every cache that shows them.\n */\n\nimport { useCallback } from 'react'\nimport { useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query'\nimport type { Arbi } from '@arbidocs/sdk/browser'\nimport { useArbi } from '../useArbi'\nimport { arbiQueryKeys } from '../hooks'\nimport { invalidateTagTables, patchWorkspaceTags } from '../tags'\nimport {\n getCachedDocuments,\n setCachedDocument,\n upsertDocuments,\n type WorkspaceDocument,\n} from './documents-cache'\nimport { loadDocuments } from './documents-loader'\nimport { FINISHED_DOCUMENT_STATUSES, isRowNewer } from './processing-order'\nimport { useArbiWsStore } from '../websocket/store'\n\nexport { FINISHED_DOCUMENT_STATUSES }\n\n/** The workspace open on `arbi`, or `null`. */\nfunction openWorkspaceId(arbi: Arbi): string | null {\n return arbi.hasWorkspace ? arbi.getWorkspaceId() : null\n}\n\n/**\n * A workspace's documents (default: the open one). Read progressively: the first page is the\n * result, the remaining pages arrive in the background (`useDocumentsLoading`). After that the list\n * is never re-read on its own (mounting, focus, reconnecting): writes, processing events and\n * {@link refreshDocuments} patch it in place, as re-reading 100k documents is slow and tells\n * nothing new. Invalidating it re-reads it.\n */\nexport function useDocuments(workspaceId?: string | null, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const qc = useQueryClient()\n const workspace = workspaceId ?? openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspace),\n queryFn: ({ signal }) => {\n if (openWorkspaceId(arbi) !== workspace)\n return Promise.reject(new Error('The selected workspace changed.'))\n return loadDocuments(qc, arbi, workspace, signal)\n },\n enabled: (options?.enabled ?? true) && !!workspace && arbi.hasWorkspace,\n staleTime: Infinity,\n refetchOnMount: false,\n refetchOnReconnect: false,\n refetchOnWindowFocus: false,\n })\n}\n\n/** How often a document still being processed is re-read (`useDocument`'s `pollWhileProcessing`). */\nexport const DOCUMENT_STATUS_POLL_MS = 4000\n\n/** Re-read a document while it is processing (a viewer waiting for its pages). */\nfunction processingInterval(doc: WorkspaceDocument | null | undefined): number | false {\n return doc?.status && !FINISHED_DOCUMENT_STATUSES.has(doc.status)\n ? DOCUMENT_STATUS_POLL_MS\n : false\n}\n\n/**\n * One document (`null`: not found or not visible). `pollWhileProcessing` re-reads it every few\n * seconds until its processing is over. Writes here keep it current.\n */\nexport function useDocument(\n docId: string | null | undefined,\n options?: { enabled?: boolean; pollWhileProcessing?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.document(docId ?? ''),\n queryFn: async (): Promise<WorkspaceDocument | null> =>\n (await arbi.documents.get([docId as string]))[0] ?? null,\n enabled: (options?.enabled ?? true) && !!docId && arbi.isLoggedIn,\n refetchInterval: options?.pollWhileProcessing\n ? (query) => processingInterval(query.state.data)\n : false,\n })\n}\n\n/**\n * The similarity at or above which two documents count as near duplicates (the Related column).\n * The server keeps every pair above 0.75 but returns only those at or above what is asked.\n */\nexport const SIMILARITY_THRESHOLD = 0.98\n\n/** Near-duplicate document pairs in the open workspace, at or above {@link SIMILARITY_THRESHOLD}. */\nexport function useSimilarDocuments(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n const workspace = openWorkspaceId(arbi) ?? ''\n return useQuery({\n queryKey: arbiQueryKeys.similarDocuments(workspace, SIMILARITY_THRESHOLD),\n queryFn: () =>\n arbi.readInWorkspace(workspace, () =>\n arbi.documents.similar({ threshold: SIMILARITY_THRESHOLD })\n ),\n enabled: (options?.enabled ?? true) && !!workspace,\n })\n}\n\n// Each re-read gets a number; only the latest one issued for a document may write it. Events can\n// return out of order, and an older read must not undo tags a newer one applied.\nlet readSeq = 0\nconst latestReadByDoc = new Map<string, number>()\n\n/**\n * Re-read `docIds` and patch them into the caches that show them: their workspace's list (added\n * when new), their own entries, and the tag list's document counts (tags the server applied, e.g.\n * AI fields). For events that name documents (a batch finished, a version saved, an upload): the\n * list is never re-read for them. A failed read leaves the caches as they were.\n */\nexport async function refreshDocuments(\n qc: QueryClient,\n arbi: Arbi,\n docIds: string[]\n): Promise<WorkspaceDocument[]> {\n if (!docIds.length) return []\n const seq = ++readSeq\n for (const id of docIds) latestReadByDoc.set(id, seq)\n try {\n const read = await arbi.documents.get(docIds)\n const fresh = read\n .filter((doc) => latestReadByDoc.get(doc.external_id) === seq)\n .map((doc) => {\n // A finished status heard live wins over a read that predates it (the row may not be\n // committed yet), never over a row that finished after it.\n const live = useArbiWsStore.getState().tasks[doc.external_id]\n return live &&\n FINISHED_DOCUMENT_STATUSES.has(live.status) &&\n doc.status !== live.status &&\n isRowNewer(doc, live) !== true\n ? { ...doc, status: live.status }\n : doc\n })\n if (!fresh.length) return []\n reconcileTagCounts(qc, fresh)\n upsertDocuments(qc, fresh)\n for (const doc of fresh) setCachedDocument(qc, doc)\n return fresh\n } catch (error) {\n // Leave the caches as they were: re-reading the whole list would shrink it to its first page.\n console.error('Re-reading documents failed; the cached ones are kept:', error)\n return []\n } finally {\n for (const id of docIds) if (latestReadByDoc.get(id) === seq) latestReadByDoc.delete(id)\n }\n}\n\n/** `refreshDocuments` on this host's cache and `Arbi`, for a component or a hook. */\nexport function useRefreshDocuments(): (docIds: string[]) => Promise<WorkspaceDocument[]> {\n const qc = useQueryClient()\n const arbi = useArbi()\n return useCallback((docIds: string[]) => refreshDocuments(qc, arbi, docIds), [qc, arbi])\n}\n\n/** Move each tag's document count by the tags the re-read documents gained or lost. */\nfunction reconcileTagCounts(qc: QueryClient, fresh: WorkspaceDocument[]): void {\n const byWorkspace = new Map<string, Map<string, number>>()\n for (const doc of fresh) {\n const cached = getCachedDocuments(qc, doc.workspace_ext_id)?.find(\n (d) => d.external_id === doc.external_id\n )\n const before = new Set((cached?.doctags ?? []).map((dt) => dt.tag_ext_id))\n const after = new Set((doc.doctags ?? []).map((dt) => dt.tag_ext_id))\n const delta = byWorkspace.get(doc.workspace_ext_id) ?? new Map<string, number>()\n for (const id of after) if (!before.has(id)) delta.set(id, (delta.get(id) ?? 0) + 1)\n for (const id of before) if (!after.has(id)) delta.set(id, (delta.get(id) ?? 0) - 1)\n byWorkspace.set(doc.workspace_ext_id, delta)\n }\n for (const [workspaceId, delta] of byWorkspace) adjustTagCounts(qc, workspaceId, delta)\n}\n\n/** Add `delta` (tag id → change) to the tags' document counts; the tag tables re-read. */\nexport function adjustTagCounts(\n qc: QueryClient,\n workspaceId: string,\n delta: Map<string, number>\n): void {\n if (![...delta.values()].some(Boolean)) return\n patchWorkspaceTags(qc, workspaceId, (tags) =>\n tags.map((tag) => {\n const change = delta.get(tag.external_id)\n return change ? { ...tag, doctag_count: Math.max(0, tag.doctag_count + change) } : tag\n })\n )\n void invalidateTagTables(qc, workspaceId)\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { normalizeMarkdown } from './chunk-WUTL62MC.js';
2
- import { normalizeCitationMarkup } from './chunk-QRCMKEE6.js';
2
+ import { normalizeCitationMarkup } from './chunk-VSCU7K4V.js';
3
3
 
4
4
  // src/ai/stored-markdown.ts
5
5
  var FENCE = /^\s*(```|~~~)/;
@@ -287,5 +287,5 @@ function isDocumentId(id) {
287
287
  }
288
288
 
289
289
  export { cleanDraftMarkdown, cleanDraftWithReport, documentVersions, findVersion, flattenChunks, isDocumentId, parseVersionRef, promoteBoldTitle, repairParsedStructure, repairParsedTitle, savedFromId, stripAgentPreamble, toArtifactVersions, unescapeMarkdown, unwrapCitationLinks, versionLabel, versionRef };
290
- //# sourceMappingURL=chunk-NNWMHMEC.js.map
291
- //# sourceMappingURL=chunk-NNWMHMEC.js.map
290
+ //# sourceMappingURL=chunk-UW2SGTI5.js.map
291
+ //# sourceMappingURL=chunk-UW2SGTI5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ai/stored-markdown.ts","../src/artifacts/versions.ts"],"names":[],"mappings":"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","file":"chunk-NNWMHMEC.js","sourcesContent":["/**\n * Helpers for markdown that is STORED (an agent's draft saved as an artifact, then read back from\n * the backend's parse). Pure and SDK-free; they sit next to `normalizeCitationMarkup`, which they\n * build on.\n *\n * Two directions:\n *\n * - Going in (`cleanDraftMarkdown` = `unwrapCitationLinks` + `stripAgentPreamble` +\n * `promoteBoldTitle`): a streamed draft carries citation links, `(*Source: ...*)` notes and\n * sometimes narration before the document. A stored letter should hold only the letter.\n * - Coming out (`unescapeMarkdown`): the backend's parse of a stored `.md` returns the text with\n * markdown punctuation backslash-escaped (`**Fees.**` comes back as `\\*\\*Fees\\.\\*\\*`).\n */\n\nimport { normalizeCitationMarkup } from './normalize-citations'\n\nconst FENCE = /^\\s*(```|~~~)/\n\n/** Run `fn` on every line outside a fenced code block. */\nfunction mapOutsideFences(text: string, fn: (line: string) => string): string {\n let inFence = false\n return text\n .split('\\n')\n .map((line) => {\n if (FENCE.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : fn(line)\n })\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Coming out: undo the parser's escaping\n// ---------------------------------------------------------------------------------------------\n\n/** A backslash followed by markdown punctuation: the only thing the parser's escaping produces. */\nconst ESCAPED_PUNCTUATION = /\\\\([\\\\`*_{}[\\]()#+\\-.!|>~<])/g\n/** The only escapes the parser puts inside an inline code span. */\nconst ESCAPED_EMPHASIS = /\\\\([*_])/g\nconst INLINE_CODE = /(`+)(?!`)(.+?)(?<!`)\\1(?!`)/g\n\n/**\n * Undo the backend's escaping of a markdown artifact: `\\*\\*Scope\\.\\*\\*` becomes `**Scope.**`.\n *\n * THE RULE. Apply this ONLY to text of an artifact that was stored from markdown (an agent draft\n * or an edited version, always uploaded as `.md`): for those the parser escapes every markdown\n * punctuation character, including the backslash itself, so removing one level of escaping is the\n * exact inverse (an author's literal `\\*` is stored as `\\\\\\*` and comes back as `\\*`). Do not\n * apply it to a PDF or Word parse, where a backslash is just a character.\n *\n * Details:\n * - Only a backslash followed by markdown punctuation (``\\ ` * _ { } [ ] ( ) # + - . ! | > ~ <``)\n * is removed; `\\n`, `C:\\temp` and a trailing backslash are left alone.\n * - Pairs are read left to right, so `\\\\*` is an escaped backslash followed by a bare `*`.\n * - Fenced code blocks are never touched (the parser does not escape inside them).\n * - Inline code spans: the parser DOES escape `*` and `_` there (`` `a*b` `` comes back as\n * `` `a\\*b` ``), so only `\\*` and `\\_` are undone inside a span; any other backslash in code\n * (`` `re\\.x` ``) is a literal and stays.\n */\nexport function unescapeMarkdown(text: string): string {\n if (!text.includes('\\\\')) return text\n return mapOutsideFences(text, (line) => {\n if (!line.includes('\\\\')) return line\n let out = ''\n let last = 0\n for (const span of line.matchAll(INLINE_CODE)) {\n const at = span.index ?? 0\n out +=\n line.slice(last, at).replace(ESCAPED_PUNCTUATION, '$1') +\n span[0].replace(ESCAPED_EMPHASIS, '$1')\n last = at + span[0].length\n }\n return out + line.slice(last).replace(ESCAPED_PUNCTUATION, '$1')\n })\n}\n\n/**\n * The parser also mangles the TITLE of a stored markdown document (seen on a real backend): the\n * first heading comes back doubled (`## # Title`) or alone inside a code fence\n * (a fence, `# Title`, a fence). Both are repaired, on the first non-blank line only, so a code\n * block or heading later in the text is never touched. Like `unescapeMarkdown`, apply it only to\n * artifacts stored from markdown.\n */\nexport function repairParsedTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const doubled = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/.exec(lines[first])\n if (doubled) {\n lines[first] = doubled[1]\n return lines.join('\\n')\n }\n if (/^\\s*```\\s*$/.test(lines[first]) && /^#{1,6}\\s+\\S/.test(lines[first + 1] ?? '')) {\n if (/^\\s*```\\s*$/.test(lines[first + 2] ?? '')) lines.splice(first + 2, 1)\n else return text\n lines.splice(first, 1)\n return lines.join('\\n')\n }\n return text\n}\n\nconst DOUBLED_HEADING = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_HEADING = /^[-*+]\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_IN_LIST = /^[-*+]\\s+[-*+]\\s+(\\S.*)$/\nconst LIST_ORDINAL = /^[-*+]\\s+(\\d{1,9})([.)])\\s+(\\S.*)$/\nconst LIST_ITEM_LINE = /^\\s*(?:[-*+]|\\d{1,9}[.)])\\s/\nconst TABLE_DELIMITER_CELL = /^:?-{1,}:?$/\n\n/** `1. a 2. b 3. c` (one line) split where the next ordinal follows: `['1. a', '2. b', '3. c']`. */\nfunction splitRunOfOrdinals(first: number, delimiter: string, rest: string): string[] {\n const items: string[] = []\n let n = first\n let remaining = rest\n for (;;) {\n const next = new RegExp(`^(.+?)\\\\s+${n + 1}\\\\${delimiter}\\\\s+(\\\\S.*)$`).exec(remaining)\n if (!next) break\n items.push(`${n}${delimiter} ${next[1]}`)\n n += 1\n remaining = next[2]\n }\n items.push(`${n}${delimiter} ${remaining}`)\n return items\n}\n\n/**\n * A table the parser put on ONE line (`| h | h | |---|---| | a | b |`, rows joined by a space, which\n * leaves one empty cell between rows) back as a pipe table. `null` when the line is not that shape.\n */\nfunction rebuildFlatTable(line: string): string[] | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null\n const cells = trimmed\n .slice(1, -1)\n .split('|')\n .map((c) => c.trim())\n const firstRule = cells.findIndex((c) => TABLE_DELIMITER_CELL.test(c))\n if (firstRule < 2 || cells[firstRule - 1] !== '') return null\n const columns = firstRule - 1\n const rows: string[][] = []\n for (let at = 0; at < cells.length; at += columns + 1) {\n const row = cells.slice(at, at + columns)\n const gap = cells[at + columns]\n if (row.length !== columns || (gap !== undefined && gap !== '')) return null\n rows.push(row)\n }\n const [header, rule, ...body] = rows\n if (!rule.every((c) => TABLE_DELIMITER_CELL.test(c))) return null\n const fmt = (row: string[]): string => `| ${row.join(' | ')} |`\n return [fmt(header), fmt(rule.map(() => '---')), ...body.map(fmt)]\n}\n\n/**\n * Undo how the backend's parse of a stored `.md` restructures it (seen on a real backend):\n * - a heading comes back doubled (`## # Title`) or as a list item (`- # Title`);\n * - every list item gets a `- ` of its own on top of the original marker, so `* a` returns as\n * `- * a` and `1. a` as `- 1. a`, which a markdown editor loads as a list inside a list item\n * (and saves as `- - a`); a run of ordinals can come back on one line (`- 1. a 2. b`);\n * - a table comes back on one line.\n * List nesting and the bullet/ordered difference of a flat `- x` cannot be recovered, so items\n * stay flat. Items of one list are kept tight (no blank line between them). Fenced code is\n * never touched. Like `unescapeMarkdown`, apply it only to artifacts stored from markdown.\n */\nexport function repairParsedStructure(text: string): string {\n const out: string[] = []\n let inFence = false\n for (const line of text.split('\\n')) {\n if (FENCE.test(line)) {\n inFence = !inFence\n out.push(line)\n continue\n }\n if (inFence) {\n out.push(line)\n continue\n }\n const table = rebuildFlatTable(line)\n if (table) {\n out.push(...table)\n continue\n }\n const heading = DOUBLED_HEADING.exec(line) ?? LIST_HEADING.exec(line)\n if (heading) {\n out.push(heading[1])\n continue\n }\n const ordinal = LIST_ORDINAL.exec(line)\n if (ordinal) {\n out.push(...splitRunOfOrdinals(Number(ordinal[1]), ordinal[2], ordinal[3]))\n continue\n }\n const nested = LIST_IN_LIST.exec(line)\n out.push(nested ? `- ${nested[1]}` : line)\n }\n // Items parsed as separate chunks arrive one blank line apart: that is one tight list.\n return out\n .filter(\n (line, i) =>\n !(\n line === '' &&\n LIST_ITEM_LINE.test(out[i - 1] ?? '') &&\n LIST_ITEM_LINE.test(out[i + 1] ?? '')\n )\n )\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Going in: clean a streamed draft before it is stored\n// ---------------------------------------------------------------------------------------------\n\n/** `(*Source: Terms.pdf*)`, `(Sources: a, b)` and the italic form `*(Source: ...)*`. */\nconst SOURCE_NOTE =\n /[ \\t]*(?:\\*+\\(\\s*Sources?\\s*:[^)\\n]*\\)\\*+|\\(\\s*\\*{0,2}\\s*Sources?\\s*:[^)\\n]*\\))/gi\nconst CITE_TOKEN = /^\\]\\(#cite-[\\w-]+\\)/\n\n/**\n * Remove the citation links of ONE line and keep every word. A link is `[text](#cite-N)`, but the\n * model also writes brackets inside the text (`[We act for [PLACEHOLDER].](#cite-1)`) and links that\n * overlap other brackets, so a regex cannot find the opening bracket. This scans the line with a\n * stack of `[`: a `](#cite-N)` takes the nearest open `[` with it (both are removed, the text\n * between stays); a plain `]` closes the nearest `[`; a `](#cite-N)` with no open `[` loses only\n * the marker. Brackets that are not part of a link are never touched.\n */\nfunction removeCitationLinks(line: string): string {\n if (!line.includes('](#cite-')) return line\n const drop = new Set<number>()\n const open: number[] = []\n for (let i = 0; i < line.length; i++) {\n const c = line[i]\n if (c === '[') open.push(i)\n else if (c === ']') {\n const token = CITE_TOKEN.exec(line.slice(i, i + 40))\n if (token) {\n const opener = open.pop()\n if (opener !== undefined) drop.add(opener)\n for (let k = i; k < i + token[0].length; k++) drop.add(k)\n i += token[0].length - 1\n } else open.pop()\n }\n }\n let out = ''\n for (let i = 0; i < line.length; i++) if (!drop.has(i)) out += line[i]\n return out\n}\n\n/** A line whose `**` do not pair up (one half was wrapped into a link) loses the stray marks. */\nfunction balanceBold(line: string): string {\n // A bold-wrapped heading (`**# Title**`) is just a heading.\n if (/^\\s*\\*\\*#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '').trim()\n if ((line.match(/\\*\\*/g)?.length ?? 0) % 2 === 0) return line\n if (/^#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '')\n return line.replace(/\\*\\*\\s*$/, '').replace(/^(\\s*(?:[-*]\\s+)?)\\*\\*(?=\\s)/, '$1')\n}\n\n/**\n * Text for storage from text that carries citations: `normalizeCitationMarkup` first (it hoists\n * list, heading and bold tokens out of the link so unwrapping cannot orphan half of a `**` pair),\n * then `[text](#cite-N)` becomes `text`, `(*Source: ...*)` notes are dropped, and a bold or\n * heading marker that lost its partner is repaired. Fenced code is left alone.\n */\nexport function unwrapCitationLinks(text: string): string {\n const withoutNotes = mapOutsideFences(text, (line) => line.replace(SOURCE_NOTE, ''))\n return mapOutsideFences(normalizeCitationMarkup(withoutNotes), (line) => {\n const unlinked = removeCitationLinks(line)\n return unlinked === line ? line : balanceBold(unlinked)\n })\n}\n\nconst HEADING = /^#{1,6}\\s+\\S/\nconst HR_ONLY = /^\\s*(?:-{3,}|\\*{3,}|_{3,})\\s*$/\n/** A whole-line bold title: `**Client Engagement Letter**`. */\nconst BOLD_LINE = /^\\*\\*[^*#].*\\*\\*$/\nconst MAX_PREAMBLE_CHARS = 900\nconst MAX_PREAMBLE_PARAGRAPHS = 4\nconst MAX_TITLE_CHARS = 100\n\n/**\n * How a paragraph of agent narration opens. An ALLOW-LIST: a paragraph that opens any other way is\n * treated as document text and never removed.\n */\nconst NARRATION_OPENER =\n /^(?:I(?:['’](?:ll|ve|m|d))?\\s|let me\\b|here(?:['’]s| is| are)\\b|below is\\b|sure[,.! ]|certainly[,.! ]|of course[,.! ]|okay[,.! ]|based on (?:the|your|my)\\b|per the (?:user|instructions?)|as requested\\b|the workspace\\b|no (?:relevant |workspace |matching )?documents?\\b|there (?:are|is) no (?:relevant |workspace )?documents?\\b|after (?:reviewing|reading|searching)\\b)/i\n\n/** Structure a covering note would not have: lists, tables, quotes, code, headings, bold, links. */\nconst STRUCTURED = /^\\s*(?:[-*+>|]|\\d{1,9}[.)]\\s|#{1,6}\\s|```|~~~)|\\*\\*|\\]\\(/m\n\n/**\n * Cut the agent's narration written BEFORE the document. Strictly non-destructive: if in doubt the\n * text is returned whole (a stray sentence is easy to delete, a lost clause is not recoverable).\n *\n * Text is removed only when ALL of these hold:\n * 1. a real markdown heading line (`# Title`, any level) follows it, and the cut stops exactly at\n * the FIRST such line (never at a bold line, never at a line that merely contains `**`);\n * 2. what precedes it is at most 4 paragraphs and 900 characters of plain prose (horizontal rules\n * between them are ignored): no list, table, quote, code, heading, bold or link;\n * 3. EVERY paragraph opens with an allow-listed narration opener: first person (\"I'll ...\",\n * \"I now have ...\"), \"Let me\", \"Here is/are\", \"Below is\", \"Sure\", \"Based on the ...\", \"Per the\n * instructions\", \"As requested\", \"The workspace ...\", \"No (relevant) documents ...\", \"There is\n * no document ...\", \"After reviewing ...\".\n * Anything else (a dateline, an address, a salutation, a sentence of the letter) keeps the text whole.\n */\nexport function stripAgentPreamble(text: string): string {\n const lines = text.split('\\n')\n const start = lines.findIndex((l) => HEADING.test(l))\n if (start <= 0) return text\n const before = lines\n .slice(0, start)\n .filter((l) => !HR_ONLY.test(l))\n .join('\\n')\n .trim()\n if (!before) return lines.slice(start).join('\\n')\n const paragraphs = before.split(/\\n\\s*\\n/).map((p) => p.trim())\n const narration =\n before.length <= MAX_PREAMBLE_CHARS &&\n paragraphs.length <= MAX_PREAMBLE_PARAGRAPHS &&\n !STRUCTURED.test(before) &&\n paragraphs.every((p) => NARRATION_OPENER.test(p))\n return narration ? lines.slice(start).join('\\n') : text\n}\n\n/**\n * Make the document's title a real heading: the FIRST non-blank line of the text, when it is a\n * short whole-line bold title (`**Letter**`, even with a stray inner `**`), becomes `# Letter`.\n * Nothing else is ever promoted: not a later line, not a mid-sentence fragment (the title must\n * start with a capital or digit, be at most 100 characters, hold no sentence break and not end in\n * `,` `;` or `:`), and a document that already opens with a heading is left alone.\n */\nexport function promoteBoldTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const line = lines[first].trim()\n if (!BOLD_LINE.test(line)) return text\n const title = line.replace(/\\*\\*/g, '').trim()\n if (\n title.length === 0 ||\n title.length > MAX_TITLE_CHARS ||\n !/^[\\p{Lu}\\d]/u.test(title) ||\n /[,;:]$/.test(title) ||\n /[.!?]\\s+\\S/.test(title)\n ) {\n return text\n }\n lines[first] = `# ${title}`\n return lines.join('\\n')\n}\n\n/** Tidy headings only: strip stray bold marks from heading lines (`# **Title**`). */\nfunction cleanHeadings(text: string): string {\n return mapOutsideFences(text, (line) =>\n /^\\s*#{1,6}\\s/.test(line) ? line.replace(/\\*\\*/g, '').trim() : line\n )\n}\n\n/** Which stage of the cleanup produced the text that is returned. */\nexport type DraftCleanStage = 'cleaned' | 'unwrapped' | 'raw'\n\nexport interface DraftCleanReport {\n /** What to store. */\n text: string\n /**\n * `cleaned`: the full cleanup. `unwrapped`: only the citation links were removed (the preamble or\n * title step was rejected by the guard). `raw`: the input as streamed (even link removal was\n * rejected).\n */\n stage: DraftCleanStage\n /** Length of the returned text over the length of the input without its citation markup. */\n ratio: number\n /** Which steps changed the text before the guard (for logs). */\n changedBy: ('citations' | 'preamble' | 'title')[]\n /** The guard rejected a step because it would have lost content. */\n guarded: boolean\n}\n\nconst MIN_RATIO = 0.7\nconst countMatches = (text: string, re: RegExp): number => text.match(re)?.length ?? 0\nconst LIST_NUMBER = /^\\s*\\d{1,9}[.)]\\s/gm\nconst HEADING_LINE = /^#{1,6}\\s/gm\n/** The text with only its citation markup gone: the floor no cleanup may go far under. */\nconst withoutCitationMarkup = (raw: string): string =>\n mapOutsideFences(raw.replace(SOURCE_NOTE, ''), removeCitationLinks).trim()\nconst tidy = (text: string): string => text.replace(/\\n{3,}/g, '\\n\\n').trim()\n/** `after` is `before` with a leading part removed (a prefix cut, never a cut in the middle). */\nconst isPrefixCut = (before: string, after: string): boolean =>\n before.trimEnd().endsWith(after.trim())\n/** Nothing structural was lost: headings and numbered items are all still there. */\nconst keepsStructure = (candidate: string, reference: string): boolean =>\n countMatches(candidate, LIST_NUMBER) >= countMatches(reference, LIST_NUMBER) &&\n countMatches(candidate, HEADING_LINE) >= countMatches(reference, HEADING_LINE)\n\n/** The three text steps of the cleanup; replaceable so the guard can be tested. */\nexport interface DraftCleanSteps {\n unwrap: (text: string) => string\n strip: (text: string) => string\n promote: (text: string) => string\n}\nconst DEFAULT_CLEAN_STEPS: DraftCleanSteps = {\n unwrap: unwrapCitationLinks,\n strip: stripAgentPreamble,\n promote: promoteBoldTitle,\n}\n\n/**\n * `cleanDraftMarkdown` with a safety net and a report, for storing a streamed draft. Each stage is\n * accepted only if it provably cost nothing but narration and citation markup:\n * - links removed: at least 70% of the text length remains and no heading or numbered item is lost\n * (else `raw`, the input exactly as streamed);\n * - narration removed: only a pure prefix of the text may go, and nothing structural;\n * - title and heading tidy: at least 70% of the text remains and no heading or numbered item is lost.\n * A rejected stage falls back to the previous one (`cleaned` -> `unwrapped` -> `raw`).\n */\nexport function cleanDraftWithReport(\n raw: string,\n steps: DraftCleanSteps = DEFAULT_CLEAN_STEPS\n): DraftCleanReport {\n const floor = withoutCitationMarkup(raw)\n const ratio = (t: string): number => (floor.length ? t.length / floor.length : 1)\n const unwrapped = tidy(steps.unwrap(raw))\n const stripped = tidy(steps.strip(unwrapped))\n const titled = tidy(cleanHeadings(steps.promote(stripped)))\n const changedBy: DraftCleanReport['changedBy'] = []\n if (unwrapped !== raw.trim()) changedBy.push('citations')\n if (stripped !== unwrapped) changedBy.push('preamble')\n if (titled !== stripped) changedBy.push('title')\n\n const unwrappedOk = unwrapped.length >= MIN_RATIO * floor.length && keepsStructure(unwrapped, raw)\n if (!unwrappedOk) return { text: raw, stage: 'raw', ratio: 1, changedBy, guarded: true }\n const strippedOk =\n stripped === unwrapped ||\n (isPrefixCut(unwrapped, stripped) && keepsStructure(stripped, unwrapped))\n const titledOk = titled.length >= MIN_RATIO * stripped.length && keepsStructure(titled, stripped)\n if (strippedOk && titledOk) {\n return { text: titled, stage: 'cleaned', ratio: ratio(titled), changedBy, guarded: false }\n }\n return { text: unwrapped, stage: 'unwrapped', ratio: ratio(unwrapped), changedBy, guarded: true }\n}\n\n/**\n * Everything a streamed draft needs before it is stored as the artifact's first version:\n * `unwrapCitationLinks`, `stripAgentPreamble`, `promoteBoldTitle`, clean headings, collapsed blank\n * runs, trimmed, under the guard of `cleanDraftWithReport` (use it to know which stage was kept).\n */\nexport function cleanDraftMarkdown(raw: string): string {\n return cleanDraftWithReport(raw).text\n}\n","/**\n * Versions of a document. A document keeps ONE id for its whole life; its versions live inside it\n * (`current_version` + `versions`, numbered 1..n). A version is named by a version reference\n * `doc-…@v{n}`; a plain document id means its current version. The workspace list carries every\n * document's `versions`, and `GET /v1/document/{id}/versions` (`arbi.documents.versions`) the same\n * list on its own.\n */\n\nimport { repairParsedStructure, repairParsedTitle, unescapeMarkdown } from '../ai/stored-markdown'\nimport { normalizeMarkdown } from './normalize-markdown'\n\n/** One version entry as the API returns it (a subset of `DocVersion`). */\nexport interface DocVersionEntry {\n n: number\n file_name?: string | null\n created_at?: string | null\n reason?: string | null\n /** The version an edit started from, when it was not the previous one. */\n made_from?: number | null\n is_current?: boolean | null\n /** The assistant message whose turn made this version, and its thread (none: a person's). */\n source_message_ext_id?: string | null\n conversation_ext_id?: string | null\n}\n\n/** The fields of a workspace document the version list needs (a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n current_version?: number | null\n versions?: readonly DocVersionEntry[] | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n /** The version reference `doc-…@v{n}`: what opening or comparing this version names. */\n id: string\n /** The document (the same for every version). */\n docId: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** 1-based version number within the document. */\n number: number\n /** upload | edit | signed | sync */\n reason: string\n isCurrent: boolean\n /** The version this one was saved from (an older one than the previous version when restored). */\n savedFromId?: string | null\n /** The thread (and its message) whose turn made this version; none for a person's. */\n thread?: { conversationId: string; messageId: string | null } | null\n}\n\nconst VERSION_REF = /^(doc-[A-Za-z0-9]+)@v([1-9][0-9]*)$/\n\n/** `doc-…@v{n}`: a reference to version `n` of a document. */\nexport function versionRef(docId: string, version: number): string {\n return `${docId}@v${version}`\n}\n\n/**\n * Split a reference into the document and the version it names. A plain document id (or anything\n * else) names no version: the document's current one.\n */\nexport function parseVersionRef(ref: string | null | undefined): {\n docId: string\n version: number | null\n} {\n const match = VERSION_REF.exec(ref ?? '')\n if (!match) return { docId: ref ?? '', version: null }\n return { docId: match[1], version: Number(match[2]) }\n}\n\n/** The version a version was saved from: `made_from`, else the one before it. */\nexport function savedFromId(docId: string, entry: DocVersionEntry): string | null {\n if (entry.made_from) return versionRef(docId, entry.made_from)\n return entry.n > 1 ? versionRef(docId, entry.n - 1) : null\n}\n\n/** A document's version entries (oldest first) as plain version rows. */\nexport function toArtifactVersions(\n docId: string | null | undefined,\n entries: readonly DocVersionEntry[] | null | undefined,\n currentVersion?: number | null\n): ArtifactVersion[] {\n if (!docId) return []\n const current = currentVersion ?? entries?.find((e) => e.is_current)?.n ?? null\n return [...(entries ?? [])]\n .sort((a, b) => a.n - b.n)\n .map((e) => ({\n id: versionRef(docId, e.n),\n docId,\n name: e.file_name ?? '',\n createdAt: e.created_at ?? '',\n number: e.n,\n reason: e.reason ?? 'upload',\n isCurrent: current != null ? e.n === current : !!e.is_current,\n savedFromId: savedFromId(docId, e),\n thread: e.conversation_ext_id\n ? { conversationId: e.conversation_ext_id, messageId: e.source_message_ext_id ?? null }\n : null,\n }))\n}\n\n/** The versions of a listed document, oldest first (`[]` when the document is not given). */\nexport function documentVersions(doc: VersionedDoc | null | undefined): ArtifactVersion[] {\n if (!doc?.external_id) return []\n const entries = doc.versions?.length\n ? doc.versions\n : [{ n: doc.current_version ?? 1, file_name: doc.file_name, created_at: doc.created_at }]\n return toArtifactVersions(doc.external_id, entries, doc.current_version ?? null)\n}\n\n/** The row `ref` names: an exact version, or (a plain document id) the current version. */\nexport function findVersion(\n versions: readonly ArtifactVersion[],\n ref: string | null | undefined\n): ArtifactVersion | undefined {\n if (!ref) return undefined\n const { docId, version } = parseVersionRef(ref)\n return version == null\n ? versions.find((v) => v.docId === docId && v.isCurrent)\n : versions.find((v) => v.docId === docId && v.number === version)\n}\n\n/**\n * \"v2\": the version number `ref` names. `null` when there is nothing to tell apart (the document\n * has a single version, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n ref: string | null | undefined\n): string | null {\n if (!ref || versions.length <= 1) return null\n const version = findVersion(versions, ref)\n return version ? `v${version.number}` : null\n}\n\n/**\n * Join parsed chunks into one markdown text (blank line between chunks).\n *\n * `unescape: true` for an artifact stored from markdown: the backend's parse of a `.md` escapes\n * markdown punctuation, which `unescapeMarkdown` undoes (see its rule), and mangles its title\n * (`repairParsedTitle`, `repairParsedStructure`: doubled headings, `- ` stacked on list markers,\n * one-line tables), then normalised. Leave it off for the parse\n * of a PDF or Word file.\n */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined,\n options?: { unescape?: boolean }\n): string {\n const text = (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n if (!options?.unescape) return text\n // Canonical spelling last, so the text an editor starts from is what a save would persist.\n return normalizeMarkdown(\n repairParsedStructure(repairParsedTitle(unescapeMarkdown(text)))\n ).replace(/\\n$/, '')\n}\n\n/** The backend's pattern for a document id. Anything else (a streamed draft's placeholder) is local. */\nconst DOC_ID = /^doc/\n\n/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */\nexport function isDocumentId(id: string | null | undefined): id is string {\n return !!id && DOC_ID.test(id)\n}\n"]}
1
+ {"version":3,"sources":["../src/ai/stored-markdown.ts","../src/artifacts/versions.ts"],"names":[],"mappings":"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","file":"chunk-UW2SGTI5.js","sourcesContent":["/**\n * Helpers for markdown that is STORED (an agent's draft saved as an artifact, then read back from\n * the backend's parse). Pure and SDK-free; they sit next to `normalizeCitationMarkup`, which they\n * build on.\n *\n * Two directions:\n *\n * - Going in (`cleanDraftMarkdown` = `unwrapCitationLinks` + `stripAgentPreamble` +\n * `promoteBoldTitle`): a streamed draft carries citation links, `(*Source: ...*)` notes and\n * sometimes narration before the document. A stored letter should hold only the letter.\n * - Coming out (`unescapeMarkdown`): the backend's parse of a stored `.md` returns the text with\n * markdown punctuation backslash-escaped (`**Fees.**` comes back as `\\*\\*Fees\\.\\*\\*`).\n */\n\nimport { normalizeCitationMarkup } from './normalize-citations'\n\nconst FENCE = /^\\s*(```|~~~)/\n\n/** Run `fn` on every line outside a fenced code block. */\nfunction mapOutsideFences(text: string, fn: (line: string) => string): string {\n let inFence = false\n return text\n .split('\\n')\n .map((line) => {\n if (FENCE.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : fn(line)\n })\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Coming out: undo the parser's escaping\n// ---------------------------------------------------------------------------------------------\n\n/** A backslash followed by markdown punctuation: the only thing the parser's escaping produces. */\nconst ESCAPED_PUNCTUATION = /\\\\([\\\\`*_{}[\\]()#+\\-.!|>~<])/g\n/** The only escapes the parser puts inside an inline code span. */\nconst ESCAPED_EMPHASIS = /\\\\([*_])/g\nconst INLINE_CODE = /(`+)(?!`)(.+?)(?<!`)\\1(?!`)/g\n\n/**\n * Undo the backend's escaping of a markdown artifact: `\\*\\*Scope\\.\\*\\*` becomes `**Scope.**`.\n *\n * THE RULE. Apply this ONLY to text of an artifact that was stored from markdown (an agent draft\n * or an edited version, always uploaded as `.md`): for those the parser escapes every markdown\n * punctuation character, including the backslash itself, so removing one level of escaping is the\n * exact inverse (an author's literal `\\*` is stored as `\\\\\\*` and comes back as `\\*`). Do not\n * apply it to a PDF or Word parse, where a backslash is just a character.\n *\n * Details:\n * - Only a backslash followed by markdown punctuation (``\\ ` * _ { } [ ] ( ) # + - . ! | > ~ <``)\n * is removed; `\\n`, `C:\\temp` and a trailing backslash are left alone.\n * - Pairs are read left to right, so `\\\\*` is an escaped backslash followed by a bare `*`.\n * - Fenced code blocks are never touched (the parser does not escape inside them).\n * - Inline code spans: the parser DOES escape `*` and `_` there (`` `a*b` `` comes back as\n * `` `a\\*b` ``), so only `\\*` and `\\_` are undone inside a span; any other backslash in code\n * (`` `re\\.x` ``) is a literal and stays.\n */\nexport function unescapeMarkdown(text: string): string {\n if (!text.includes('\\\\')) return text\n return mapOutsideFences(text, (line) => {\n if (!line.includes('\\\\')) return line\n let out = ''\n let last = 0\n for (const span of line.matchAll(INLINE_CODE)) {\n const at = span.index ?? 0\n out +=\n line.slice(last, at).replace(ESCAPED_PUNCTUATION, '$1') +\n span[0].replace(ESCAPED_EMPHASIS, '$1')\n last = at + span[0].length\n }\n return out + line.slice(last).replace(ESCAPED_PUNCTUATION, '$1')\n })\n}\n\n/**\n * The parser also mangles the TITLE of a stored markdown document (seen on a real backend): the\n * first heading comes back doubled (`## # Title`) or alone inside a code fence\n * (a fence, `# Title`, a fence). Both are repaired, on the first non-blank line only, so a code\n * block or heading later in the text is never touched. Like `unescapeMarkdown`, apply it only to\n * artifacts stored from markdown.\n */\nexport function repairParsedTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const doubled = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/.exec(lines[first])\n if (doubled) {\n lines[first] = doubled[1]\n return lines.join('\\n')\n }\n if (/^\\s*```\\s*$/.test(lines[first]) && /^#{1,6}\\s+\\S/.test(lines[first + 1] ?? '')) {\n if (/^\\s*```\\s*$/.test(lines[first + 2] ?? '')) lines.splice(first + 2, 1)\n else return text\n lines.splice(first, 1)\n return lines.join('\\n')\n }\n return text\n}\n\nconst DOUBLED_HEADING = /^#{1,6}\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_HEADING = /^[-*+]\\s+(#{1,6}\\s+\\S.*)$/\nconst LIST_IN_LIST = /^[-*+]\\s+[-*+]\\s+(\\S.*)$/\nconst LIST_ORDINAL = /^[-*+]\\s+(\\d{1,9})([.)])\\s+(\\S.*)$/\nconst LIST_ITEM_LINE = /^\\s*(?:[-*+]|\\d{1,9}[.)])\\s/\nconst TABLE_DELIMITER_CELL = /^:?-{1,}:?$/\n\n/** `1. a 2. b 3. c` (one line) split where the next ordinal follows: `['1. a', '2. b', '3. c']`. */\nfunction splitRunOfOrdinals(first: number, delimiter: string, rest: string): string[] {\n const items: string[] = []\n let n = first\n let remaining = rest\n for (;;) {\n const next = new RegExp(`^(.+?)\\\\s+${n + 1}\\\\${delimiter}\\\\s+(\\\\S.*)$`).exec(remaining)\n if (!next) break\n items.push(`${n}${delimiter} ${next[1]}`)\n n += 1\n remaining = next[2]\n }\n items.push(`${n}${delimiter} ${remaining}`)\n return items\n}\n\n/**\n * A table the parser put on ONE line (`| h | h | |---|---| | a | b |`, rows joined by a space, which\n * leaves one empty cell between rows) back as a pipe table. `null` when the line is not that shape.\n */\nfunction rebuildFlatTable(line: string): string[] | null {\n const trimmed = line.trim()\n if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) return null\n const cells = trimmed\n .slice(1, -1)\n .split('|')\n .map((c) => c.trim())\n const firstRule = cells.findIndex((c) => TABLE_DELIMITER_CELL.test(c))\n if (firstRule < 2 || cells[firstRule - 1] !== '') return null\n const columns = firstRule - 1\n const rows: string[][] = []\n for (let at = 0; at < cells.length; at += columns + 1) {\n const row = cells.slice(at, at + columns)\n const gap = cells[at + columns]\n if (row.length !== columns || (gap !== undefined && gap !== '')) return null\n rows.push(row)\n }\n const [header, rule, ...body] = rows\n if (!rule.every((c) => TABLE_DELIMITER_CELL.test(c))) return null\n const fmt = (row: string[]): string => `| ${row.join(' | ')} |`\n return [fmt(header), fmt(rule.map(() => '---')), ...body.map(fmt)]\n}\n\n/**\n * Undo how the backend's parse of a stored `.md` restructures it (seen on a real backend):\n * - a heading comes back doubled (`## # Title`) or as a list item (`- # Title`);\n * - every list item gets a `- ` of its own on top of the original marker, so `* a` returns as\n * `- * a` and `1. a` as `- 1. a`, which a markdown editor loads as a list inside a list item\n * (and saves as `- - a`); a run of ordinals can come back on one line (`- 1. a 2. b`);\n * - a table comes back on one line.\n * List nesting and the bullet/ordered difference of a flat `- x` cannot be recovered, so items\n * stay flat. Items of one list are kept tight (no blank line between them). Fenced code is\n * never touched. Like `unescapeMarkdown`, apply it only to artifacts stored from markdown.\n */\nexport function repairParsedStructure(text: string): string {\n const out: string[] = []\n let inFence = false\n for (const line of text.split('\\n')) {\n if (FENCE.test(line)) {\n inFence = !inFence\n out.push(line)\n continue\n }\n if (inFence) {\n out.push(line)\n continue\n }\n const table = rebuildFlatTable(line)\n if (table) {\n out.push(...table)\n continue\n }\n const heading = DOUBLED_HEADING.exec(line) ?? LIST_HEADING.exec(line)\n if (heading) {\n out.push(heading[1])\n continue\n }\n const ordinal = LIST_ORDINAL.exec(line)\n if (ordinal) {\n out.push(...splitRunOfOrdinals(Number(ordinal[1]), ordinal[2], ordinal[3]))\n continue\n }\n const nested = LIST_IN_LIST.exec(line)\n out.push(nested ? `- ${nested[1]}` : line)\n }\n // Items parsed as separate chunks arrive one blank line apart: that is one tight list.\n return out\n .filter(\n (line, i) =>\n !(\n line === '' &&\n LIST_ITEM_LINE.test(out[i - 1] ?? '') &&\n LIST_ITEM_LINE.test(out[i + 1] ?? '')\n )\n )\n .join('\\n')\n}\n\n// ---------------------------------------------------------------------------------------------\n// Going in: clean a streamed draft before it is stored\n// ---------------------------------------------------------------------------------------------\n\n/** `(*Source: Terms.pdf*)`, `(Sources: a, b)` and the italic form `*(Source: ...)*`. */\nconst SOURCE_NOTE =\n /[ \\t]*(?:\\*+\\(\\s*Sources?\\s*:[^)\\n]*\\)\\*+|\\(\\s*\\*{0,2}\\s*Sources?\\s*:[^)\\n]*\\))/gi\nconst CITE_TOKEN = /^\\]\\(#cite-[\\w-]+\\)/\n\n/**\n * Remove the citation links of ONE line and keep every word. A link is `[text](#cite-N)`, but the\n * model also writes brackets inside the text (`[We act for [PLACEHOLDER].](#cite-1)`) and links that\n * overlap other brackets, so a regex cannot find the opening bracket. This scans the line with a\n * stack of `[`: a `](#cite-N)` takes the nearest open `[` with it (both are removed, the text\n * between stays); a plain `]` closes the nearest `[`; a `](#cite-N)` with no open `[` loses only\n * the marker. Brackets that are not part of a link are never touched.\n */\nfunction removeCitationLinks(line: string): string {\n if (!line.includes('](#cite-')) return line\n const drop = new Set<number>()\n const open: number[] = []\n for (let i = 0; i < line.length; i++) {\n const c = line[i]\n if (c === '[') open.push(i)\n else if (c === ']') {\n const token = CITE_TOKEN.exec(line.slice(i, i + 40))\n if (token) {\n const opener = open.pop()\n if (opener !== undefined) drop.add(opener)\n for (let k = i; k < i + token[0].length; k++) drop.add(k)\n i += token[0].length - 1\n } else open.pop()\n }\n }\n let out = ''\n for (let i = 0; i < line.length; i++) if (!drop.has(i)) out += line[i]\n return out\n}\n\n/** A line whose `**` do not pair up (one half was wrapped into a link) loses the stray marks. */\nfunction balanceBold(line: string): string {\n // A bold-wrapped heading (`**# Title**`) is just a heading.\n if (/^\\s*\\*\\*#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '').trim()\n if ((line.match(/\\*\\*/g)?.length ?? 0) % 2 === 0) return line\n if (/^#{1,6}\\s/.test(line)) return line.replace(/\\*\\*/g, '')\n return line.replace(/\\*\\*\\s*$/, '').replace(/^(\\s*(?:[-*]\\s+)?)\\*\\*(?=\\s)/, '$1')\n}\n\n/**\n * Text for storage from text that carries citations: `normalizeCitationMarkup` first (it hoists\n * list, heading and bold tokens out of the link so unwrapping cannot orphan half of a `**` pair),\n * then `[text](#cite-N)` becomes `text`, `(*Source: ...*)` notes are dropped, and a bold or\n * heading marker that lost its partner is repaired. Fenced code is left alone.\n */\nexport function unwrapCitationLinks(text: string): string {\n const withoutNotes = mapOutsideFences(text, (line) => line.replace(SOURCE_NOTE, ''))\n return mapOutsideFences(normalizeCitationMarkup(withoutNotes), (line) => {\n const unlinked = removeCitationLinks(line)\n return unlinked === line ? line : balanceBold(unlinked)\n })\n}\n\nconst HEADING = /^#{1,6}\\s+\\S/\nconst HR_ONLY = /^\\s*(?:-{3,}|\\*{3,}|_{3,})\\s*$/\n/** A whole-line bold title: `**Client Engagement Letter**`. */\nconst BOLD_LINE = /^\\*\\*[^*#].*\\*\\*$/\nconst MAX_PREAMBLE_CHARS = 900\nconst MAX_PREAMBLE_PARAGRAPHS = 4\nconst MAX_TITLE_CHARS = 100\n\n/**\n * How a paragraph of agent narration opens. An ALLOW-LIST: a paragraph that opens any other way is\n * treated as document text and never removed.\n */\nconst NARRATION_OPENER =\n /^(?:I(?:['’](?:ll|ve|m|d))?\\s|let me\\b|here(?:['’]s| is| are)\\b|below is\\b|sure[,.! ]|certainly[,.! ]|of course[,.! ]|okay[,.! ]|based on (?:the|your|my)\\b|per the (?:user|instructions?)|as requested\\b|the workspace\\b|no (?:relevant |workspace |matching )?documents?\\b|there (?:are|is) no (?:relevant |workspace )?documents?\\b|after (?:reviewing|reading|searching)\\b)/i\n\n/** Structure a covering note would not have: lists, tables, quotes, code, headings, bold, links. */\nconst STRUCTURED = /^\\s*(?:[-*+>|]|\\d{1,9}[.)]\\s|#{1,6}\\s|```|~~~)|\\*\\*|\\]\\(/m\n\n/**\n * Cut the agent's narration written BEFORE the document. Strictly non-destructive: if in doubt the\n * text is returned whole (a stray sentence is easy to delete, a lost clause is not recoverable).\n *\n * Text is removed only when ALL of these hold:\n * 1. a real markdown heading line (`# Title`, any level) follows it, and the cut stops exactly at\n * the FIRST such line (never at a bold line, never at a line that merely contains `**`);\n * 2. what precedes it is at most 4 paragraphs and 900 characters of plain prose (horizontal rules\n * between them are ignored): no list, table, quote, code, heading, bold or link;\n * 3. EVERY paragraph opens with an allow-listed narration opener: first person (\"I'll ...\",\n * \"I now have ...\"), \"Let me\", \"Here is/are\", \"Below is\", \"Sure\", \"Based on the ...\", \"Per the\n * instructions\", \"As requested\", \"The workspace ...\", \"No (relevant) documents ...\", \"There is\n * no document ...\", \"After reviewing ...\".\n * Anything else (a dateline, an address, a salutation, a sentence of the letter) keeps the text whole.\n */\nexport function stripAgentPreamble(text: string): string {\n const lines = text.split('\\n')\n const start = lines.findIndex((l) => HEADING.test(l))\n if (start <= 0) return text\n const before = lines\n .slice(0, start)\n .filter((l) => !HR_ONLY.test(l))\n .join('\\n')\n .trim()\n if (!before) return lines.slice(start).join('\\n')\n const paragraphs = before.split(/\\n\\s*\\n/).map((p) => p.trim())\n const narration =\n before.length <= MAX_PREAMBLE_CHARS &&\n paragraphs.length <= MAX_PREAMBLE_PARAGRAPHS &&\n !STRUCTURED.test(before) &&\n paragraphs.every((p) => NARRATION_OPENER.test(p))\n return narration ? lines.slice(start).join('\\n') : text\n}\n\n/**\n * Make the document's title a real heading: the FIRST non-blank line of the text, when it is a\n * short whole-line bold title (`**Letter**`, even with a stray inner `**`), becomes `# Letter`.\n * Nothing else is ever promoted: not a later line, not a mid-sentence fragment (the title must\n * start with a capital or digit, be at most 100 characters, hold no sentence break and not end in\n * `,` `;` or `:`), and a document that already opens with a heading is left alone.\n */\nexport function promoteBoldTitle(text: string): string {\n const lines = text.split('\\n')\n const first = lines.findIndex((l) => l.trim())\n if (first < 0) return text\n const line = lines[first].trim()\n if (!BOLD_LINE.test(line)) return text\n const title = line.replace(/\\*\\*/g, '').trim()\n if (\n title.length === 0 ||\n title.length > MAX_TITLE_CHARS ||\n !/^[\\p{Lu}\\d]/u.test(title) ||\n /[,;:]$/.test(title) ||\n /[.!?]\\s+\\S/.test(title)\n ) {\n return text\n }\n lines[first] = `# ${title}`\n return lines.join('\\n')\n}\n\n/** Tidy headings only: strip stray bold marks from heading lines (`# **Title**`). */\nfunction cleanHeadings(text: string): string {\n return mapOutsideFences(text, (line) =>\n /^\\s*#{1,6}\\s/.test(line) ? line.replace(/\\*\\*/g, '').trim() : line\n )\n}\n\n/** Which stage of the cleanup produced the text that is returned. */\nexport type DraftCleanStage = 'cleaned' | 'unwrapped' | 'raw'\n\nexport interface DraftCleanReport {\n /** What to store. */\n text: string\n /**\n * `cleaned`: the full cleanup. `unwrapped`: only the citation links were removed (the preamble or\n * title step was rejected by the guard). `raw`: the input as streamed (even link removal was\n * rejected).\n */\n stage: DraftCleanStage\n /** Length of the returned text over the length of the input without its citation markup. */\n ratio: number\n /** Which steps changed the text before the guard (for logs). */\n changedBy: ('citations' | 'preamble' | 'title')[]\n /** The guard rejected a step because it would have lost content. */\n guarded: boolean\n}\n\nconst MIN_RATIO = 0.7\nconst countMatches = (text: string, re: RegExp): number => text.match(re)?.length ?? 0\nconst LIST_NUMBER = /^\\s*\\d{1,9}[.)]\\s/gm\nconst HEADING_LINE = /^#{1,6}\\s/gm\n/** The text with only its citation markup gone: the floor no cleanup may go far under. */\nconst withoutCitationMarkup = (raw: string): string =>\n mapOutsideFences(raw.replace(SOURCE_NOTE, ''), removeCitationLinks).trim()\nconst tidy = (text: string): string => text.replace(/\\n{3,}/g, '\\n\\n').trim()\n/** `after` is `before` with a leading part removed (a prefix cut, never a cut in the middle). */\nconst isPrefixCut = (before: string, after: string): boolean =>\n before.trimEnd().endsWith(after.trim())\n/** Nothing structural was lost: headings and numbered items are all still there. */\nconst keepsStructure = (candidate: string, reference: string): boolean =>\n countMatches(candidate, LIST_NUMBER) >= countMatches(reference, LIST_NUMBER) &&\n countMatches(candidate, HEADING_LINE) >= countMatches(reference, HEADING_LINE)\n\n/** The three text steps of the cleanup; replaceable so the guard can be tested. */\nexport interface DraftCleanSteps {\n unwrap: (text: string) => string\n strip: (text: string) => string\n promote: (text: string) => string\n}\nconst DEFAULT_CLEAN_STEPS: DraftCleanSteps = {\n unwrap: unwrapCitationLinks,\n strip: stripAgentPreamble,\n promote: promoteBoldTitle,\n}\n\n/**\n * `cleanDraftMarkdown` with a safety net and a report, for storing a streamed draft. Each stage is\n * accepted only if it provably cost nothing but narration and citation markup:\n * - links removed: at least 70% of the text length remains and no heading or numbered item is lost\n * (else `raw`, the input exactly as streamed);\n * - narration removed: only a pure prefix of the text may go, and nothing structural;\n * - title and heading tidy: at least 70% of the text remains and no heading or numbered item is lost.\n * A rejected stage falls back to the previous one (`cleaned` -> `unwrapped` -> `raw`).\n */\nexport function cleanDraftWithReport(\n raw: string,\n steps: DraftCleanSteps = DEFAULT_CLEAN_STEPS\n): DraftCleanReport {\n const floor = withoutCitationMarkup(raw)\n const ratio = (t: string): number => (floor.length ? t.length / floor.length : 1)\n const unwrapped = tidy(steps.unwrap(raw))\n const stripped = tidy(steps.strip(unwrapped))\n const titled = tidy(cleanHeadings(steps.promote(stripped)))\n const changedBy: DraftCleanReport['changedBy'] = []\n if (unwrapped !== raw.trim()) changedBy.push('citations')\n if (stripped !== unwrapped) changedBy.push('preamble')\n if (titled !== stripped) changedBy.push('title')\n\n const unwrappedOk = unwrapped.length >= MIN_RATIO * floor.length && keepsStructure(unwrapped, raw)\n if (!unwrappedOk) return { text: raw, stage: 'raw', ratio: 1, changedBy, guarded: true }\n const strippedOk =\n stripped === unwrapped ||\n (isPrefixCut(unwrapped, stripped) && keepsStructure(stripped, unwrapped))\n const titledOk = titled.length >= MIN_RATIO * stripped.length && keepsStructure(titled, stripped)\n if (strippedOk && titledOk) {\n return { text: titled, stage: 'cleaned', ratio: ratio(titled), changedBy, guarded: false }\n }\n return { text: unwrapped, stage: 'unwrapped', ratio: ratio(unwrapped), changedBy, guarded: true }\n}\n\n/**\n * Everything a streamed draft needs before it is stored as the artifact's first version:\n * `unwrapCitationLinks`, `stripAgentPreamble`, `promoteBoldTitle`, clean headings, collapsed blank\n * runs, trimmed, under the guard of `cleanDraftWithReport` (use it to know which stage was kept).\n */\nexport function cleanDraftMarkdown(raw: string): string {\n return cleanDraftWithReport(raw).text\n}\n","/**\n * Versions of a document. A document keeps ONE id for its whole life; its versions live inside it\n * (`current_version` + `versions`, numbered 1..n). A version is named by a version reference\n * `doc-…@v{n}`; a plain document id means its current version. The workspace list carries every\n * document's `versions`, and `GET /v1/document/{id}/versions` (`arbi.documents.versions`) the same\n * list on its own.\n */\n\nimport { repairParsedStructure, repairParsedTitle, unescapeMarkdown } from '../ai/stored-markdown'\nimport { normalizeMarkdown } from './normalize-markdown'\n\n/** One version entry as the API returns it (a subset of `DocVersion`). */\nexport interface DocVersionEntry {\n n: number\n file_name?: string | null\n created_at?: string | null\n reason?: string | null\n /** The version an edit started from, when it was not the previous one. */\n made_from?: number | null\n is_current?: boolean | null\n /** The assistant message whose turn made this version, and its thread (none: a person's). */\n source_message_ext_id?: string | null\n conversation_ext_id?: string | null\n}\n\n/** The fields of a workspace document the version list needs (a subset of the API type). */\nexport interface VersionedDoc {\n external_id?: string | null\n current_version?: number | null\n versions?: readonly DocVersionEntry[] | null\n file_name?: string | null\n created_at?: string | null\n}\n\n/** One row of a version list. Matches `VersionEntry` of `@arbidocs/blocks/artifacts`. */\nexport interface ArtifactVersion {\n /** The version reference `doc-…@v{n}`: what opening or comparing this version names. */\n id: string\n /** The document (the same for every version). */\n docId: string\n /** File name as stored. */\n name: string\n /** ISO timestamp. */\n createdAt: string\n /** 1-based version number within the document. */\n number: number\n /** upload | edit | signed | sync */\n reason: string\n isCurrent: boolean\n /** The version this one was saved from (an older one than the previous version when restored). */\n savedFromId?: string | null\n /** The thread (and its message) whose turn made this version; none for a person's. */\n thread?: { conversationId: string; messageId: string | null } | null\n}\n\nconst VERSION_REF = /^(doc-[A-Za-z0-9]+)@v([1-9][0-9]*)$/\n\n/** `doc-…@v{n}`: a reference to version `n` of a document. */\nexport function versionRef(docId: string, version: number): string {\n return `${docId}@v${version}`\n}\n\n/**\n * Split a reference into the document and the version it names. A plain document id (or anything\n * else) names no version: the document's current one.\n */\nexport function parseVersionRef(ref: string | null | undefined): {\n docId: string\n version: number | null\n} {\n const match = VERSION_REF.exec(ref ?? '')\n if (!match) return { docId: ref ?? '', version: null }\n return { docId: match[1], version: Number(match[2]) }\n}\n\n/** The version a version was saved from: `made_from`, else the one before it. */\nexport function savedFromId(docId: string, entry: DocVersionEntry): string | null {\n if (entry.made_from) return versionRef(docId, entry.made_from)\n return entry.n > 1 ? versionRef(docId, entry.n - 1) : null\n}\n\n/** A document's version entries (oldest first) as plain version rows. */\nexport function toArtifactVersions(\n docId: string | null | undefined,\n entries: readonly DocVersionEntry[] | null | undefined,\n currentVersion?: number | null\n): ArtifactVersion[] {\n if (!docId) return []\n const current = currentVersion ?? entries?.find((e) => e.is_current)?.n ?? null\n return [...(entries ?? [])]\n .sort((a, b) => a.n - b.n)\n .map((e) => ({\n id: versionRef(docId, e.n),\n docId,\n name: e.file_name ?? '',\n createdAt: e.created_at ?? '',\n number: e.n,\n reason: e.reason ?? 'upload',\n isCurrent: current != null ? e.n === current : !!e.is_current,\n savedFromId: savedFromId(docId, e),\n thread: e.conversation_ext_id\n ? { conversationId: e.conversation_ext_id, messageId: e.source_message_ext_id ?? null }\n : null,\n }))\n}\n\n/** The versions of a listed document, oldest first (`[]` when the document is not given). */\nexport function documentVersions(doc: VersionedDoc | null | undefined): ArtifactVersion[] {\n if (!doc?.external_id) return []\n const entries = doc.versions?.length\n ? doc.versions\n : [{ n: doc.current_version ?? 1, file_name: doc.file_name, created_at: doc.created_at }]\n return toArtifactVersions(doc.external_id, entries, doc.current_version ?? null)\n}\n\n/** The row `ref` names: an exact version, or (a plain document id) the current version. */\nexport function findVersion(\n versions: readonly ArtifactVersion[],\n ref: string | null | undefined\n): ArtifactVersion | undefined {\n if (!ref) return undefined\n const { docId, version } = parseVersionRef(ref)\n return version == null\n ? versions.find((v) => v.docId === docId && v.isCurrent)\n : versions.find((v) => v.docId === docId && v.number === version)\n}\n\n/**\n * \"v2\": the version number `ref` names. `null` when there is nothing to tell apart (the document\n * has a single version, or it is unknown), so unversioned documents stay unlabelled.\n */\nexport function versionLabel(\n versions: readonly ArtifactVersion[],\n ref: string | null | undefined\n): string | null {\n if (!ref || versions.length <= 1) return null\n const version = findVersion(versions, ref)\n return version ? `v${version.number}` : null\n}\n\n/**\n * Join parsed chunks into one markdown text (blank line between chunks).\n *\n * `unescape: true` for an artifact stored from markdown: the backend's parse of a `.md` escapes\n * markdown punctuation, which `unescapeMarkdown` undoes (see its rule), and mangles its title\n * (`repairParsedTitle`, `repairParsedStructure`: doubled headings, `- ` stacked on list markers,\n * one-line tables), then normalised. Leave it off for the parse\n * of a PDF or Word file.\n */\nexport function flattenChunks(\n chunks: readonly { content?: string | null }[] | null | undefined,\n options?: { unescape?: boolean }\n): string {\n const text = (chunks ?? []).map((c) => (c.content ?? '').trim()).join('\\n\\n')\n if (!options?.unescape) return text\n // Canonical spelling last, so the text an editor starts from is what a save would persist.\n return normalizeMarkdown(\n repairParsedStructure(repairParsedTitle(unescapeMarkdown(text)))\n ).replace(/\\n$/, '')\n}\n\n/** The backend's pattern for a document id. Anything else (a streamed draft's placeholder) is local. */\nconst DOC_ID = /^doc/\n\n/** Is `id` a real, saved document id? Local drafts have placeholder ids and no backend document. */\nexport function isDocumentId(id: string | null | undefined): id is string {\n return !!id && DOC_ID.test(id)\n}\n"]}
@@ -1,3 +1,11 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ // src/host/context.ts
4
+ var ArbiHostContext = createContext({});
5
+ function useHostConfigRecord() {
6
+ return useContext(ArbiHostContext);
7
+ }
8
+
1
9
  // src/ai/normalize-citations.ts
2
10
  var SOURCE_RESIDUE = /\(\*+\s*(Sources?\s*:[^\n]*?)\s*\*+\)/g;
3
11
  var CITE_CLOSE = /^\]\((#cite-[\w-]+)\)/;
@@ -168,6 +176,6 @@ function closeOpenEmphasis(markdown) {
168
176
  return head + line + "**";
169
177
  }
170
178
 
171
- export { closeOpenEmphasis, normalizeCitationMarkup, trimOpenCitation };
172
- //# sourceMappingURL=chunk-QRCMKEE6.js.map
173
- //# sourceMappingURL=chunk-QRCMKEE6.js.map
179
+ export { ArbiHostContext, closeOpenEmphasis, normalizeCitationMarkup, trimOpenCitation, useHostConfigRecord };
180
+ //# sourceMappingURL=chunk-VSCU7K4V.js.map
181
+ //# sourceMappingURL=chunk-VSCU7K4V.js.map