@arbidocs/react 0.4.32 → 0.4.34

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 (46) hide show
  1. package/README.md +1 -1
  2. package/dist/artifacts/index.cjs +17 -17
  3. package/dist/artifacts/index.js +5 -5
  4. package/dist/{chunk-EOOHRPFM.cjs → chunk-775VGSKN.cjs} +59 -10
  5. package/dist/chunk-775VGSKN.cjs.map +1 -0
  6. package/dist/{chunk-OXUFBF5W.js → chunk-FHTSDPQV.js} +405 -123
  7. package/dist/chunk-FHTSDPQV.js.map +1 -0
  8. package/dist/{chunk-6YSHODMG.js → chunk-FOEYFNQ4.js} +59 -10
  9. package/dist/chunk-FOEYFNQ4.js.map +1 -0
  10. package/dist/{chunk-6BLXIF4R.cjs → chunk-PW7GGG7E.cjs} +9 -7
  11. package/dist/chunk-PW7GGG7E.cjs.map +1 -0
  12. package/dist/{chunk-3AK4QJ62.cjs → chunk-QJLXFDKV.cjs} +412 -125
  13. package/dist/chunk-QJLXFDKV.cjs.map +1 -0
  14. package/dist/{chunk-OBTCAI4E.js → chunk-UDOPD3GK.js} +12 -4
  15. package/dist/chunk-UDOPD3GK.js.map +1 -0
  16. package/dist/{chunk-NDG44JWI.js → chunk-V3A7JDJV.js} +8 -6
  17. package/dist/chunk-V3A7JDJV.js.map +1 -0
  18. package/dist/{chunk-YSZJCWDD.cjs → chunk-Z4M7JB4L.cjs} +12 -4
  19. package/dist/chunk-Z4M7JB4L.cjs.map +1 -0
  20. package/dist/{index-CcbVSNSP.d.cts → index-C7OqcKY3.d.cts} +3 -1
  21. package/dist/{index-CcbVSNSP.d.ts → index-C7OqcKY3.d.ts} +3 -1
  22. package/dist/{index-C99tcxue.d.ts → index-CUxIcC5j.d.cts} +19 -7
  23. package/dist/{index-C99tcxue.d.cts → index-CUxIcC5j.d.ts} +19 -7
  24. package/dist/index.cjs +463 -634
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +60 -10
  27. package/dist/index.d.ts +60 -10
  28. package/dist/index.js +26 -213
  29. package/dist/index.js.map +1 -1
  30. package/dist/shell/index.cjs +6 -6
  31. package/dist/shell/index.d.cts +1 -1
  32. package/dist/shell/index.d.ts +1 -1
  33. package/dist/shell/index.js +1 -1
  34. package/dist/ui/index.cjs +134 -130
  35. package/dist/ui/index.d.cts +1 -1
  36. package/dist/ui/index.d.ts +1 -1
  37. package/dist/ui/index.js +2 -2
  38. package/package.json +3 -3
  39. package/dist/chunk-3AK4QJ62.cjs.map +0 -1
  40. package/dist/chunk-6BLXIF4R.cjs.map +0 -1
  41. package/dist/chunk-6YSHODMG.js.map +0 -1
  42. package/dist/chunk-EOOHRPFM.cjs.map +0 -1
  43. package/dist/chunk-NDG44JWI.js.map +0 -1
  44. package/dist/chunk-OBTCAI4E.js.map +0 -1
  45. package/dist/chunk-OXUFBF5W.js.map +0 -1
  46. package/dist/chunk-YSZJCWDD.cjs.map +0 -1
@@ -80,7 +80,7 @@ function splitMarkdownBlocks(content) {
80
80
 
81
81
  // src/ai/normalize-citations.ts
82
82
  var SOURCE_RESIDUE = /\(\*+\s*(Sources?\s*:[^\n]*?)\s*\*+\)/g;
83
- var CITE_LINK = /\[((?:[^[\]\n]|\[[^[\]\n]*\])+)\]\((#cite-[\w-]+)\)/g;
83
+ var CITE_CLOSE = /^\]\((#cite-[\w-]+)\)/;
84
84
  var BLOCK_MARKER = /^(?:[-*+]|\d{1,9}[.)]|#{1,6})[ \t]+/;
85
85
  var LEADING_EMPHASIS = /^(?:\*\*|__|\*|_)+/;
86
86
  var TRAILING_EMPHASIS = /(\*\*|__|\*|_)(:?)$/;
@@ -112,6 +112,11 @@ function hoistFromLink(text, before, after) {
112
112
  body = body.slice(marker[0].length);
113
113
  }
114
114
  }
115
+ const closer = /^(\*\*|__|\*|_)(\s+)(?=\S)/.exec(body);
116
+ if (closer && countToken(before + prefix, closer[1]) % 2 === 1) {
117
+ prefix += closer[1] + closer[2];
118
+ body = body.slice(closer[0].length);
119
+ }
115
120
  const leading = LEADING_EMPHASIS.exec(body);
116
121
  if (leading) {
117
122
  let kept = "";
@@ -147,17 +152,61 @@ function hoistFromLink(text, before, after) {
147
152
  suffix = trailing[0];
148
153
  }
149
154
  }
155
+ if (!suffix) {
156
+ for (const token of ["**", "*"]) {
157
+ const at = lastUnmatchedOpener(body, token);
158
+ if (at > 0 && countToken(after, token) % 2 === 1) {
159
+ suffix = " " + body.slice(at);
160
+ body = body.slice(0, at).trimEnd();
161
+ break;
162
+ }
163
+ }
164
+ }
150
165
  return [prefix, body, suffix];
151
166
  }
167
+ function lastUnmatchedOpener(text, token) {
168
+ if (countToken(text, token) % 2 === 0) return -1;
169
+ const pattern = token === "**" ? /\*\*(?=\S)/g : /(?<!\*)\*(?![*\s])/g;
170
+ let at = -1;
171
+ for (const m of text.matchAll(pattern)) at = m.index ?? -1;
172
+ return at;
173
+ }
174
+ function findCiteLinks(line) {
175
+ const links = [];
176
+ const open = [];
177
+ for (let i = 0; i < line.length; i++) {
178
+ const c = line[i];
179
+ if (c === "[") open.push(i);
180
+ else if (c === "]") {
181
+ const opener = open.pop();
182
+ const close = CITE_CLOSE.exec(line.slice(i, i + 40));
183
+ if (opener !== void 0 && close) {
184
+ links.push({
185
+ start: opener,
186
+ end: i + close[0].length,
187
+ text: line.slice(opener + 1, i),
188
+ href: close[1]
189
+ });
190
+ i += close[0].length - 1;
191
+ }
192
+ }
193
+ }
194
+ return links.sort((x, y) => x.start - y.start);
195
+ }
152
196
  function normalizeLine(line) {
153
197
  if (!line.includes("](#cite-")) return line;
154
- return line.replace(CITE_LINK, (match, text, href, offset) => {
155
- const before = line.slice(0, offset);
156
- const after = line.slice(offset + match.length);
157
- const [prefix, body, suffix] = hoistFromLink(text, before, after);
158
- if (!prefix && !suffix && body === text) return match;
159
- return `${prefix}[${body}](${href})${suffix}`;
160
- });
198
+ let out = "";
199
+ let last = 0;
200
+ for (const link of findCiteLinks(line)) {
201
+ if (link.start < last) continue;
202
+ const before = line.slice(0, link.start);
203
+ const after = line.slice(link.end);
204
+ const [prefix, body, suffix] = hoistFromLink(link.text, before, after);
205
+ out += line.slice(last, link.start);
206
+ out += `${prefix}[${body}](${link.href})${suffix}`;
207
+ last = link.end;
208
+ }
209
+ return out + line.slice(last);
161
210
  }
162
211
  function normalizeSourceResidue(line) {
163
212
  return line.includes("(*") ? line.replace(SOURCE_RESIDUE, "*($1)*") : line;
@@ -400,5 +449,5 @@ function MarkdownRendererComponent({
400
449
  var MarkdownRenderer = React.memo(MarkdownRendererComponent);
401
450
 
402
451
  export { MarkdownRenderer, MarkdownStreamingContext, closeOpenEmphasis, markdownBaseComponents, normalizeCitationMarkup, splitMarkdownBlocks, trimOpenCitation };
403
- //# sourceMappingURL=chunk-6YSHODMG.js.map
404
- //# sourceMappingURL=chunk-6YSHODMG.js.map
452
+ //# sourceMappingURL=chunk-FOEYFNQ4.js.map
453
+ //# sourceMappingURL=chunk-FOEYFNQ4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai/markdown-base-components.tsx","../src/ai/markdown-streaming-context.ts","../src/ai/split-markdown-blocks.ts","../src/ai/normalize-citations.ts","../src/ai/MarkdownRenderer.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-FOEYFNQ4.js","sourcesContent":["import React from 'react'\nimport type { Components } from 'react-markdown'\n\n/**\n * Brand-neutral presentational component overrides for react-markdown, shared by\n * every markdown surface in the workspace (the monolith's `MarkdownRenderer` and\n * the AI kit's `AiMarkdown`). One house style for headings, lists, tables and the\n * inline text elements — token-based, so it themes per app.\n *\n * Deliberately excluded (kept per-consumer): `a` (external-link confirm vs\n * plain), `code`/`pre` (rich CodeBlock + Mermaid vs inline), `span` (doc-entity\n * pills), and `del`/`ins`/`mark` (general emphasis vs redline tracked-changes) —\n * these differ by intent or carry heavy/coupled behaviour, so each renderer owns\n * them and spreads this base underneath.\n */\nexport const markdownBaseComponents: Partial<Components> = {\n h1: ({ children, ...props }: React.ComponentPropsWithoutRef<'h1'>) => (\n <h1 className=\"text-lg font-semibold\" data-testid=\"markdown-heading-1\" {...props}>\n {children}\n </h1>\n ),\n h2: ({ children, ...props }: React.ComponentPropsWithoutRef<'h2'>) => (\n <h2 className=\"font-semibold text-base\" data-testid=\"markdown-heading-2\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }: React.ComponentPropsWithoutRef<'h3'>) => (\n <h3 className=\"font-semibold text-base\" data-testid=\"markdown-heading-3\" {...props}>\n {children}\n </h3>\n ),\n h4: ({ children, ...props }: React.ComponentPropsWithoutRef<'h4'>) => (\n <h4 className=\"font-semibold text-base\" {...props}>\n {children}\n </h4>\n ),\n h5: ({ children, ...props }: React.ComponentPropsWithoutRef<'h5'>) => (\n <h5 className=\"font-medium\" {...props}>\n {children}\n </h5>\n ),\n strong: ({ children, ...props }: React.ComponentPropsWithoutRef<'strong'>) => (\n <strong className=\"font-semibold\" {...props}>\n {children}\n </strong>\n ),\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-primary pl-4\" {...props}>\n {children}\n </blockquote>\n ),\n ol: ({ children, ...props }: React.ComponentPropsWithoutRef<'ol'>) => (\n <ol className=\"list-decimal space-y-2 pl-6\" data-testid=\"markdown-ordered-list\" {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }: React.ComponentPropsWithoutRef<'ul'>) => (\n <ul className=\"list-none space-y-2 pl-6\" data-testid=\"markdown-unordered-list\" {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }: React.ComponentPropsWithoutRef<'li'>) => (\n <li className=\"my-1.5\" {...props}>\n {children}\n </li>\n ),\n table: ({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) => (\n <table data-testid=\"markdown-table\" {...props}>\n {children}\n </table>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th {...props}>{children}</th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td {...props}>{children}</td>\n ),\n tr: ({ children, ...props }: React.ComponentPropsWithoutRef<'tr'>) => (\n <tr {...props}>{children}</tr>\n ),\n p: ({ children, ...props }: React.ComponentPropsWithoutRef<'p'>) => (\n <p className=\"whitespace-pre-wrap\" {...props}>\n {children}\n </p>\n ),\n hr: (props: React.ComponentPropsWithoutRef<'hr'>) => (\n <hr className=\"border-foreground/20\" {...props} />\n ),\n sup: ({ children, ...props }: React.ComponentPropsWithoutRef<'sup'>) => (\n <sup className=\"text-xs\" {...props}>\n {children}\n </sup>\n ),\n sub: ({ children, ...props }: React.ComponentPropsWithoutRef<'sub'>) => (\n <sub className=\"text-xs\" {...props}>\n {children}\n </sub>\n ),\n div: ({ children, className, ...props }: React.ComponentPropsWithoutRef<'div'>) => (\n <div className={className} {...props}>\n {children}\n </div>\n ),\n br: (props: React.ComponentPropsWithoutRef<'br'>) => <br {...props} />,\n kbd: ({ children, ...props }: React.ComponentPropsWithoutRef<'kbd'>) => (\n <kbd\n className=\"px-1.5 py-0.5 text-xs font-mono bg-muted border border-border rounded\"\n {...props}\n >\n {children}\n </kbd>\n ),\n abbr: ({ children, title, ...props }: React.ComponentPropsWithoutRef<'abbr'>) => (\n <abbr title={title} className=\"underline decoration-dotted cursor-help\" {...props}>\n {children}\n </abbr>\n ),\n cite: ({ children, ...props }: React.ComponentPropsWithoutRef<'cite'>) => (\n <cite className=\"italic\" {...props}>\n {children}\n </cite>\n ),\n}\n","import { createContext } from 'react'\n\n/**\n * Signals to `MarkdownRenderer`'s component overrides that the surrounding\n * message is still streaming tokens. Heavy renderers can defer their work while\n * this is true to avoid burning CPU on partially complete fences and to keep the\n * UI responsive during long generations.\n *\n * Default `false` means non-streaming usages (parsed documents, static answers,\n * DM bubbles) get the full rendering with no behaviour change.\n */\nexport const MarkdownStreamingContext = createContext(false)\n","/**\n * Splits a markdown string into top-level blocks at `\\n\\n` boundaries.\n *\n * Streaming AI responses arrive token-by-token; passing the full string to\n * react-markdown re-parses the entire AST on every flush. By splitting into\n * blocks and memoizing each, only the trailing (still-growing) block re-parses\n * — completed blocks stay frozen in the DOM.\n *\n * The split avoids three correctness pitfalls:\n * - never splits inside an open ``` code fence (would corrupt the language)\n * - never splits between two adjacent list items (would render as two lists)\n * - never splits between two blockquote lines (would render as two quotes)\n */\nconst LIST_ITEM_RE = /^\\s*([-*+]|\\d+[.)])\\s/\nconst BLOCKQUOTE_RE = /^\\s*>/\n\nexport function splitMarkdownBlocks(content: string): string[] {\n if (!content) return []\n const blocks: string[] = []\n let start = 0\n let inFence = false\n let i = 0\n while (i < content.length) {\n if (content.startsWith('```', i)) {\n inFence = !inFence\n i += 3\n continue\n }\n if (!inFence && content[i] === '\\n' && content[i + 1] === '\\n') {\n const before = content.slice(start, i)\n const lastLine = before.slice(before.lastIndexOf('\\n') + 1)\n const afterStart = i + 2\n const nextNewline = content.indexOf('\\n', afterStart)\n const nextLine = content.slice(afterStart, nextNewline === -1 ? undefined : nextNewline)\n const bothListItems = LIST_ITEM_RE.test(lastLine) && LIST_ITEM_RE.test(nextLine)\n const bothBlockquotes = BLOCKQUOTE_RE.test(lastLine) && BLOCKQUOTE_RE.test(nextLine)\n if (bothListItems || bothBlockquotes) {\n i += 2\n continue\n }\n blocks.push(content.slice(start, afterStart))\n start = afterStart\n i = afterStart\n continue\n }\n i++\n }\n if (start < content.length) blocks.push(content.slice(start))\n return blocks\n}\n","/**\n * Citation markup normaliser.\n *\n * The backend marks a cited statement as a markdown link, `[statement](#cite-N)`, and the\n * statement can include the markdown that surrounds it: a list marker, a heading marker or the\n * opener of a bold/italic span whose closer sits after the link. Inside link text those tokens\n * are not parsed as block or inline syntax, so they show literally and break lists and bold:\n *\n * [- **Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * `normalizeCitationMarkup` hoists the leading tokens out of the link text (and a trailing\n * emphasis closer after it), so the link only wraps the words:\n *\n * - **[Claimed quantum (by Claimant)](#cite-1):** **USD 47 million**\n *\n * It is conservative: emphasis that opens and closes inside the link text is valid markdown and\n * is left alone, an opener is only hoisted when its closer follows on the same line, and fenced\n * code blocks are never touched. The result is idempotent.\n *\n * It also tidies the residue the model leaves when it cites in prose as well: a literal\n * `(*Source: Award.pdf, p. 12*)` shows its asterisks, because `(*` does not open emphasis. It\n * becomes the italic note `*(Source: Award.pdf, p. 12)*`.\n */\n\nconst SOURCE_RESIDUE = /\\(\\*+\\s*(Sources?\\s*:[^\\n]*?)\\s*\\*+\\)/g\n\nconst CITE_CLOSE = /^\\]\\((#cite-[\\w-]+)\\)/\nconst BLOCK_MARKER = /^(?:[-*+]|\\d{1,9}[.)]|#{1,6})[ \\t]+/\nconst LEADING_EMPHASIS = /^(?:\\*\\*|__|\\*|_)+/\nconst TRAILING_EMPHASIS = /(\\*\\*|__|\\*|_)(:?)$/\n\n/** Occurrences of `token` in `text`; a single `*` is counted outside any `**` pair. */\nfunction countToken(text: string, token: string): number {\n const double = token + token\n if (token.length === 2) return text.split(token).length - 1\n const withoutDouble = text.split(double).join('')\n return withoutDouble.split(token).length - 1\n}\n\n/** Split a run of emphasis characters (`***`, `**`, `*`...) into its parser-level tokens. */\nfunction emphasisTokens(run: string): string[] {\n const char = run[0]\n const tokens: string[] = []\n let rest = run\n while (rest.length > 0) {\n const size = rest.length >= 2 ? 2 : 1\n tokens.push(char.repeat(size))\n rest = rest.slice(size)\n }\n return tokens\n}\n\nfunction hoistFromLink(text: string, before: string, after: string): [string, string, string] {\n let body = text\n let prefix = ''\n let suffix = ''\n\n if (before.trim() === '') {\n const marker = BLOCK_MARKER.exec(body)\n if (marker) {\n prefix += marker[0]\n body = body.slice(marker[0].length)\n }\n }\n\n // The link opened inside an emphasis span: `*Sources:[* Letter](#cite-2)`. A leading token that\n // the text before the link left open, and that is followed by a space, is the span's CLOSER (an\n // opener cannot precede a space), so it moves out in front of the link with its space.\n const closer = /^(\\*\\*|__|\\*|_)(\\s+)(?=\\S)/.exec(body)\n if (closer && countToken(before + prefix, closer[1]) % 2 === 1) {\n prefix += closer[1] + closer[2]\n body = body.slice(closer[0].length)\n }\n\n const leading = LEADING_EMPHASIS.exec(body)\n if (leading) {\n let kept = ''\n let rest = body.slice(leading[0].length)\n for (const token of emphasisTokens(leading[0]).reverse()) {\n // Balanced inside the link text: valid as written.\n if (countToken(rest, token) % 2 === 1) {\n kept = token + kept\n continue\n }\n // Unmatched here: hoist only if the line closes it after the link.\n if (countToken(after, token) % 2 === 1) prefix += token\n else kept = token + kept\n }\n body = kept + rest\n rest = ''\n }\n\n // A span opened before the link and closed inside it (`**Spence v. [Costa Rica** arbitration.]`)\n // cannot close across the link boundary: move the words up to the closer out of the link.\n for (const token of ['**', '__']) {\n const at = body.indexOf(token)\n if (at === -1 || countToken(body, token) % 2 === 0) continue\n if (countToken(before + prefix, token) % 2 === 0) continue\n const rest = body.slice(at + token.length)\n if (!/[\\p{L}\\p{N}]/u.test(rest)) continue\n prefix +=\n body.slice(0, at + token.length) + rest.slice(0, rest.length - rest.trimStart().length)\n body = rest.trimStart()\n break\n }\n\n const trailing = TRAILING_EMPHASIS.exec(body)\n if (trailing) {\n const token = trailing[1]\n const inner = body.slice(0, body.length - trailing[0].length)\n const openedBefore = countToken(before + prefix, token) % 2 === 1\n if (countToken(inner, token) % 2 === 0 && openedBefore) {\n body = inner\n suffix = trailing[0]\n }\n }\n\n // The link ends inside an emphasis span that closes after it: `*(Source](#cite-1): a.md)*`. The\n // unmatched opener and the words after it leave the link, so the span opens and closes in the\n // same text again: `[words](#cite-1) *(Source: a.md)*`.\n if (!suffix) {\n for (const token of ['**', '*']) {\n const at = lastUnmatchedOpener(body, token)\n if (at > 0 && countToken(after, token) % 2 === 1) {\n suffix = ' ' + body.slice(at)\n body = body.slice(0, at).trimEnd()\n break\n }\n }\n }\n\n return [prefix, body, suffix]\n}\n\n/** Index of the last `token` in `text` that opens emphasis (followed by a non-space) and has no closer. */\nfunction lastUnmatchedOpener(text: string, token: string): number {\n if (countToken(text, token) % 2 === 0) return -1\n const pattern = token === '**' ? /\\*\\*(?=\\S)/g : /(?<!\\*)\\*(?![*\\s])/g\n let at = -1\n for (const m of text.matchAll(pattern)) at = m.index ?? -1\n return at\n}\n\ninterface CiteLink {\n start: number\n end: number\n text: string\n href: string\n}\n\n/**\n * The `[text](#cite-N)` links of a line. The text may hold brackets of its own\n * (`[2. **[PLACEHOLDER]** names the claimant.](#cite-3)`), so a regex cannot find the opener: a\n * stack of `[` is scanned, and a `](#cite-N)` takes the nearest open one.\n */\nfunction findCiteLinks(line: string): CiteLink[] {\n const links: CiteLink[] = []\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 opener = open.pop()\n const close = CITE_CLOSE.exec(line.slice(i, i + 40))\n if (opener !== undefined && close) {\n links.push({\n start: opener,\n end: i + close[0].length,\n text: line.slice(opener + 1, i),\n href: close[1],\n })\n i += close[0].length - 1\n }\n }\n }\n return links.sort((x, y) => x.start - y.start)\n}\n\nfunction normalizeLine(line: string): string {\n if (!line.includes('](#cite-')) return line\n let out = ''\n let last = 0\n for (const link of findCiteLinks(line)) {\n // A link inside another link's text is part of that text.\n if (link.start < last) continue\n const before = line.slice(0, link.start)\n const after = line.slice(link.end)\n const [prefix, body, suffix] = hoistFromLink(link.text, before, after)\n out += line.slice(last, link.start)\n out += `${prefix}[${body}](${link.href})${suffix}`\n last = link.end\n }\n return out + line.slice(last)\n}\n\nfunction normalizeSourceResidue(line: string): string {\n return line.includes('(*') ? line.replace(SOURCE_RESIDUE, '*($1)*') : line\n}\n\nexport function normalizeCitationMarkup(markdown: string): string {\n if (!markdown.includes('](#cite-') && !markdown.includes('(*')) return markdown\n let inFence = false\n return markdown\n .split('\\n')\n .map((line) => {\n if (/^\\s*(```|~~~)/.test(line)) {\n inFence = !inFence\n return line\n }\n return inFence ? line : normalizeSourceResidue(normalizeLine(line))\n })\n .join('\\n')\n}\n\n/** A trailing, still-open `[words](#cite-N` marker (or an unclosed `[words`) on the last line. */\nconst OPEN_CITATION_TAIL = /\\[[^\\]\\n]*(?:\\](?:\\((?:#(?:c(?:i(?:t(?:e(?:-[\\w-]*)?)?)?)?)?)?)?)?$/\n\n/**\n * Drops an unfinished citation marker from the end of text that is still streaming (or was\n * stopped mid-marker), so `[Change of control](#cite-` never shows as raw markup: the words appear\n * once the marker is complete. Complete markers and everything else are left alone.\n */\nexport function trimOpenCitation(markdown: string): string {\n return markdown.replace(OPEN_CITATION_TAIL, '')\n}\n\n/** `**` pairs outside inline code in a line. */\nfunction boldMarks(line: string): number {\n return (line.replace(/`[^`]*`/g, '').match(/\\*\\*/g) ?? []).length\n}\n\n/**\n * Makes the tail of text that is still streaming (or was stopped) render cleanly: a `**` opened\n * in the last line and not yet closed (`| Valuation | **[USD 6.2 million](#cite-2)`) would show as\n * literal asterisks until its closer arrives, because an unclosed emphasis is not emphasis. The\n * open bold is closed at the end of the line, or removed when it has no text yet (`| **`, or a\n * half-typed closer `**USD 6*`). Text with balanced emphasis, and every line but the last, is\n * left alone. Apply after `trimOpenCitation`.\n */\nexport function closeOpenEmphasis(markdown: string): string {\n const cut = markdown.lastIndexOf('\\n') + 1\n const head = markdown.slice(0, cut)\n const fences = head.split('\\n').filter((l) => /^\\s*(```|~~~)/.test(l)).length\n let line = markdown.slice(cut)\n if (fences % 2 === 1 || /^\\s*(```|~~~)/.test(line)) return markdown\n // A half-typed opener: the first `*` of `**` after a space or a cell border.\n line = line.replace(/(^|[\\s|])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n // A half-typed closer: `**USD 6*` -> the second asterisk has not arrived.\n line = line.replace(/([^*\\s])\\*$/, '$1')\n if (boldMarks(line) % 2 === 0) return head + line\n if (/\\*\\*\\s*$/.test(line)) return head + line.replace(/\\s*\\*\\*\\s*$/, ' ')\n return head + line + '**'\n}\n","import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport Markdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport rehypeRaw from 'rehype-raw'\nimport { Copy, Check } from 'lucide-react'\nimport { cn } from '../lib/utils'\nimport { markdownBaseComponents } from './markdown-base-components'\nimport { MarkdownStreamingContext } from './markdown-streaming-context'\nimport { splitMarkdownBlocks } from './split-markdown-blocks'\nimport { closeOpenEmphasis, normalizeCitationMarkup, trimOpenCitation } from './normalize-citations'\n\n/**\n * MarkdownRenderer — the single, full-featured markdown surface for the kit.\n *\n * Renders AI answers, chat/DM messages and parsed-document panes with one house\n * style: headings, paragraphs, bold/italic, ordered/unordered lists, GFM tables,\n * fenced code blocks (monospace + copy button), inline code, blockquotes, safe\n * links (`rel=\"noopener\"`, new tab) and horizontal rules.\n *\n * Styling is 100% semantic Tailwind tokens (`text-foreground`,\n * `text-muted-foreground`, `border-border`, `bg-muted`, `text-primary`) so it\n * themes per firm — no hardcoded brand colours. It sizes to its container, so it\n * looks right in a compact chat bubble and in a full-width document pane alike.\n *\n * Streaming: the content is split into block-level chunks (see\n * `splitMarkdownBlocks`) and each chunk is memoised, so streaming token updates\n * only re-parse the trailing block instead of the whole message. Pass\n * `isStreaming` to let heavy custom components defer via `MarkdownStreamingContext`.\n *\n * Extending: pass `components` to override any element (the kit's `AiMarkdown`\n * and `CitationRenderer` layer their accent links / citation popovers on top).\n */\n\nconst EDGE_FADE = '1.5rem'\n\n/**\n * A GFM table in its own horizontal scroller. The table keeps a minimum width per column\n * (`min-w-[7rem]` cells, words never broken mid-word), so on a narrow screen it scrolls sideways\n * inside this wrapper instead of squeezing cells to a letter per line. The edge(s) with more\n * content to scroll to fade out, which is the scroll hint. Wide containers are unchanged: the\n * table is `w-full` and nothing overflows.\n */\nfunction MarkdownTable({ children, ...props }: React.ComponentPropsWithoutRef<'table'>) {\n const ref = useRef<HTMLDivElement>(null)\n const [edges, setEdges] = useState({ start: false, end: false })\n const measure = useCallback(() => {\n const el = ref.current\n if (!el) return\n const start = el.scrollLeft > 1\n const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1\n setEdges((prev) => (prev.start === start && prev.end === end ? prev : { start, end }))\n }, [])\n useEffect(() => {\n const el = ref.current\n if (!el) return\n measure()\n if (typeof ResizeObserver === 'undefined') return\n const observer = new ResizeObserver(measure)\n observer.observe(el)\n if (el.firstElementChild) observer.observe(el.firstElementChild)\n return () => observer.disconnect()\n }, [measure])\n const mask =\n edges.start || edges.end\n ? `linear-gradient(to right, ${edges.start ? 'transparent' : '#000'}, #000 ${EDGE_FADE}, #000 calc(100% - ${EDGE_FADE}), ${edges.end ? 'transparent' : '#000'})`\n : undefined\n return (\n <div\n ref={ref}\n onScroll={measure}\n data-testid=\"markdown-table-scroller\"\n data-scroll-start={edges.start || undefined}\n data-scroll-end={edges.end || undefined}\n className=\"my-3 overflow-x-auto rounded-lg border border-border\"\n style={mask ? { maskImage: mask, WebkitMaskImage: mask } : undefined}\n >\n <table\n data-testid=\"markdown-table\"\n className=\"w-full border-collapse text-sm [overflow-wrap:normal] [word-break:normal]\"\n {...props}\n >\n {children}\n </table>\n </div>\n )\n}\n\n/** Fenced code block with a language label and copy-to-clipboard button. */\nfunction CodeBlock({ language, code }: { language: string; code: string }) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(code)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard unavailable (insecure context / permissions) — no-op.\n }\n }\n\n return (\n <div\n className=\"code-block relative my-3 overflow-hidden rounded-md border border-current/20 bg-current/5\"\n data-testid=\"markdown-code-block\"\n >\n <div className=\"flex items-center justify-between border-b border-current/20 px-3 py-1.5\">\n <span className=\"font-mono text-xs text-muted-foreground\">{language || 'code'}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground\"\n title={copied ? 'Copied!' : 'Copy code'}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? 'Copied' : 'Copy'}</span>\n </button>\n </div>\n <pre className=\"overflow-x-auto p-3 text-sm leading-relaxed\">\n <code className={cn('font-mono', language && `language-${language}`)}>{code}</code>\n </pre>\n </div>\n )\n}\n\n/**\n * Links. Internal hash/anchor links stay in-page; everything else opens safely in a new tab\n * (`rel=\"noopener noreferrer\"` prevents reverse-tabnabbing). A backend citation marker\n * (`#cite-N`) has no popover here: the cited words stay in the surface's own colour with a quiet\n * superscript number after them (no underline, so a cited sentence does not read as a link).\n * Pass `renderCitation` to `MarkdownRenderer` to swap in a real source popover.\n */\nfunction MarkdownLink({ href, children, ...props }: React.ComponentPropsWithoutRef<'a'>) {\n if (href?.startsWith('#cite-')) {\n return (\n <span\n className=\"cited-text after:ml-px after:align-super after:text-[0.7em] after:font-medium after:text-muted-foreground after:content-[attr(data-cite)]\"\n data-cite={href.slice(6)}\n >\n {children}\n </span>\n )\n }\n const isInternal = !href || href.startsWith('#') || href.startsWith('cite:')\n return (\n <a\n className=\"text-primary underline underline-offset-2\"\n href={href}\n {...(isInternal ? {} : { target: '_blank', rel: 'noopener noreferrer' })}\n {...props}\n >\n {children}\n </a>\n )\n}\n\n/**\n * Default component overrides. Spreads the shared brand-neutral base\n * (`markdownBaseComponents`: headings, lists, paragraphs, emphasis, hr…) and adds\n * the elements that carry behaviour or need self-contained styling: safe links,\n * code (inline + fenced), bordered tables and blockquotes. Module-scoped so the\n * reference is stable across renders and react-markdown can skip re-parsing.\n */\nconst defaultComponents: Partial<Components> = {\n ...markdownBaseComponents,\n a: MarkdownLink,\n em: ({ children, ...props }: React.ComponentPropsWithoutRef<'em'>) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n code: function MarkdownCode({\n className,\n children,\n ...props\n }: React.ComponentPropsWithoutRef<'code'>) {\n const match = /language-(\\w+)/.exec(className || '')\n if (!match) {\n return (\n <code\n className=\"rounded bg-current/10 px-1 py-0.5 font-mono text-[0.9em]\"\n data-testid=\"markdown-inline-code\"\n {...props}\n >\n {children}\n </code>\n )\n }\n return <CodeBlock language={match[1]} code={String(children).replace(/\\n$/, '')} />\n },\n // The CodeBlock renders its own <pre>; unwrap react-markdown's wrapper so we\n // don't nest <pre><pre>.\n pre: ({ children }: React.ComponentPropsWithoutRef<'pre'>) => <>{children}</>,\n blockquote: ({ children, ...props }: React.ComponentPropsWithoutRef<'blockquote'>) => (\n <blockquote className=\"border-l-2 border-border pl-4 italic text-muted-foreground\" {...props}>\n {children}\n </blockquote>\n ),\n table: MarkdownTable,\n thead: ({ children, ...props }: React.ComponentPropsWithoutRef<'thead'>) => (\n <thead className=\"bg-current/10\" {...props}>\n {children}\n </thead>\n ),\n th: ({ children, ...props }: React.ComponentPropsWithoutRef<'th'>) => (\n <th\n className=\"min-w-[7rem] border-b border-border px-3 py-2 text-left font-semibold\"\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ children, ...props }: React.ComponentPropsWithoutRef<'td'>) => (\n <td className=\"min-w-[7rem] border-b border-border px-3 py-2 align-top\" {...props}>\n {children}\n </td>\n ),\n // General emphasis marks (GFM `~~strikethrough~~` → <del>, raw <ins>/<mark>).\n del: ({ children, ...props }: React.ComponentPropsWithoutRef<'del'>) => (\n <del className=\"text-muted-foreground line-through\" {...props}>\n {children}\n </del>\n ),\n ins: ({ children, ...props }: React.ComponentPropsWithoutRef<'ins'>) => (\n <ins className=\"underline decoration-primary/60\" {...props}>\n {children}\n </ins>\n ),\n mark: ({ children, ...props }: React.ComponentPropsWithoutRef<'mark'>) => (\n <mark className=\"rounded bg-primary/15 px-0.5 text-inherit\" {...props}>\n {children}\n </mark>\n ),\n}\n\n// Stable module-scope plugin arrays so react-markdown compares them by reference\n// and skips re-running the remark/rehype pipeline when nothing else changed.\n// `rehype-raw` enables inline HTML (e.g. redline <del>/<ins>); no math/mermaid\n// plugins are bundled to keep the kit light.\nconst remarkPlugins = [remarkGfm]\nconst rehypePlugins = [rehypeRaw]\n\n/**\n * One parsed markdown block, memoised on (content, components) so already-rendered\n * blocks don't re-parse when a later block streams new tokens. This is the core\n * of the streaming-rendering optimisation.\n */\nconst MemoizedBlock = React.memo(function MarkdownBlock({\n content,\n components,\n}: {\n content: string\n components: Partial<Components>\n}) {\n return (\n <Markdown remarkPlugins={remarkPlugins} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n )\n})\n\n/** Prevents a malformed-markdown render error from crashing the whole surface. */\nclass MarkdownErrorBoundary extends React.Component<\n { fallback: React.ReactNode; children: React.ReactNode },\n { hasError: boolean }\n> {\n state = { hasError: false }\n static getDerivedStateFromError() {\n return { hasError: true }\n }\n render() {\n return this.state.hasError ? this.props.fallback : this.props.children\n }\n}\n\nexport interface MarkdownRendererProps {\n /** Markdown content to render. */\n children: string\n /** Custom component overrides merged on top of the defaults. */\n components?: Partial<Components>\n /**\n * When true, signals heavy custom components (via `MarkdownStreamingContext`)\n * to defer their work while tokens are still arriving. Defaults to false.\n */\n isStreaming?: boolean\n /**\n * Renders a citation marker `[words](#cite-N)`: `children` are the cited words, `num` the N.\n * Keep it referentially stable (`useCallback`/`useMemo`), or every block re-parses.\n */\n renderCitation?: (citation: { num: string; children: React.ReactNode }) => React.ReactNode\n /** Extra classes on the wrapper (font-size, prose width, etc.). */\n className?: string\n /** Overrides the `data-testid` on the wrapper (default `markdown-renderer`). */\n testId?: string\n}\n\nfunction MarkdownRendererComponent({\n children,\n components: customComponents,\n renderCitation,\n isStreaming = false,\n className,\n testId = 'markdown-renderer',\n}: MarkdownRendererProps) {\n const components = useMemo(() => {\n const base = customComponents\n ? { ...defaultComponents, ...customComponents }\n : defaultComponents\n if (!renderCitation) return base\n const Link = base.a ?? MarkdownLink\n return {\n ...base,\n a: (props: React.ComponentPropsWithoutRef<'a'>) =>\n props.href?.startsWith('#cite-')\n ? renderCitation({ num: props.href.slice(6), children: props.children })\n : React.createElement(Link as React.ElementType, props),\n }\n }, [customComponents, renderCitation])\n\n const blocks = useMemo(\n () =>\n splitMarkdownBlocks(\n normalizeCitationMarkup(\n isStreaming ? closeOpenEmphasis(trimOpenCitation(children)) : children\n )\n ),\n [children, isStreaming]\n )\n\n return (\n <MarkdownErrorBoundary\n fallback={<div className={cn('whitespace-pre-wrap break-words', className)}>{children}</div>}\n >\n <MarkdownStreamingContext.Provider value={isStreaming}>\n <div\n className={cn('markdown-content space-y-3 break-words leading-relaxed', className)}\n data-testid={testId}\n >\n {blocks.map((block, index) => (\n <MemoizedBlock key={index} content={block} components={components} />\n ))}\n </div>\n </MarkdownStreamingContext.Provider>\n </MarkdownErrorBoundary>\n )\n}\n\n/**\n * Memoised so a stable message in a long thread doesn't re-parse when unrelated\n * tokens arrive elsewhere; a streaming message gets a fresh `children` each flush\n * and re-renders (only its trailing block re-parses, thanks to `MemoizedBlock`).\n */\nexport const MarkdownRenderer = React.memo(MarkdownRendererComponent)\n"]}
@@ -1,17 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var chunkEOOHRPFM_cjs = require('./chunk-EOOHRPFM.cjs');
3
+ var chunk775VGSKN_cjs = require('./chunk-775VGSKN.cjs');
4
4
  var chunkZMTLGO3K_cjs = require('./chunk-ZMTLGO3K.cjs');
5
5
  var react = require('react');
6
6
  var reactQuery = require('@tanstack/react-query');
7
7
 
8
8
  // src/credits.ts
9
9
  var DEFAULT_USD_PER_CREDIT = 0.01;
10
+ var WHOLE_CREDITS_FROM = 100;
10
11
  function formatCredits(credits, options = {}) {
11
12
  const { unit = true, locale = "en-US" } = options;
12
- const whole = Math.round(Number.isFinite(credits) ? credits : 0);
13
- const digits = whole.toLocaleString(locale);
14
- return unit ? `${digits} ${whole === 1 ? "credit" : "credits"}` : digits;
13
+ const safe = Number.isFinite(credits) ? credits : 0;
14
+ const rounded = Math.abs(safe) >= WHOLE_CREDITS_FROM ? Math.round(safe) : Math.round(safe * 100) / 100;
15
+ const digits = rounded.toLocaleString(locale, { maximumFractionDigits: 2 });
16
+ return unit ? `${digits} ${rounded === 1 ? "credit" : "credits"}` : digits;
15
17
  }
16
18
  function creditsToUsd(credits, usdPerCredit = DEFAULT_USD_PER_CREDIT) {
17
19
  return credits * usdPerCredit;
@@ -461,7 +463,7 @@ function balanceBold(line) {
461
463
  }
462
464
  function unwrapCitationLinks(text) {
463
465
  const withoutNotes = mapOutsideFences(text, (line) => line.replace(SOURCE_NOTE, ""));
464
- return mapOutsideFences(chunkEOOHRPFM_cjs.normalizeCitationMarkup(withoutNotes), (line) => {
466
+ return mapOutsideFences(chunk775VGSKN_cjs.normalizeCitationMarkup(withoutNotes), (line) => {
465
467
  const unlinked = removeCitationLinks(line);
466
468
  return unlinked === line ? line : balanceBold(unlinked);
467
469
  });
@@ -573,5 +575,5 @@ exports.useThumbnails = useThumbnails;
573
575
  exports.useUserUsageToday = useUserUsageToday;
574
576
  exports.useWorkspaceUsers = useWorkspaceUsers;
575
577
  exports.useWorkspaces = useWorkspaces;
576
- //# sourceMappingURL=chunk-6BLXIF4R.cjs.map
577
- //# sourceMappingURL=chunk-6BLXIF4R.cjs.map
578
+ //# sourceMappingURL=chunk-PW7GGG7E.cjs.map
579
+ //# sourceMappingURL=chunk-PW7GGG7E.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/credits.ts","../src/hooks.ts","../src/ai/stored-markdown.ts"],"names":["useArbi","useQuery","useMutation","useQueryClient","useQueries","useMemo","normalizeCitationMarkup"],"mappings":"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","file":"chunk-PW7GGG7E.cjs","sourcesContent":["/**\n * Credits: the unit the ARBI backend reports AI usage in.\n *\n * The usage endpoints (`/v1/user/projects/{id}/usage`, `/me/usage/today`) convert the metered USD\n * spend into credits at the API boundary (fractional, rounded to 2 decimals, because a small\n * deployment spends well under one credit a day): 1 credit = `CREDITS_TO_AI_USD`, which is $0.01 on\n * a default deployment. The fields are still named `spend` / `total_spend` in the schema, but they\n * hold CREDITS, never dollars. Label them as credits; use {@link creditsToUsd} only when a\n * dollar figure is genuinely wanted, with the deployment's own rate.\n */\n\n/** Dollars per credit on a default deployment (`CREDITS_TO_AI_USD`). */\nexport const DEFAULT_USD_PER_CREDIT = 0.01\n\nexport interface FormatCreditsOptions {\n /** Append the unit (\"12 credits\"). Default true; pass false inside a column headed \"Credits\". */\n unit?: boolean\n /** BCP 47 locale for the digit grouping. Default `en-US`. */\n locale?: string\n}\n\n/** Amounts at or above this show as whole credits; below it, up to 2 decimals. */\nconst WHOLE_CREDITS_FROM = 100\n\n/**\n * \"0.47 credits\" / \"1 credit\" / \"1.5 credits\" / \"1,235 credits\". The backend reports fractional\n * credits (2 decimals). Amounts under 100 keep up to 2 decimals with trailing zeros trimmed;\n * amounts of 100 and over round to whole credits. Only exactly 1 is singular.\n */\nexport function formatCredits(credits: number, options: FormatCreditsOptions = {}): string {\n const { unit = true, locale = 'en-US' } = options\n const safe = Number.isFinite(credits) ? credits : 0\n const rounded =\n Math.abs(safe) >= WHOLE_CREDITS_FROM ? Math.round(safe) : Math.round(safe * 100) / 100\n const digits = rounded.toLocaleString(locale, { maximumFractionDigits: 2 })\n return unit ? `${digits} ${rounded === 1 ? 'credit' : 'credits'}` : digits\n}\n\n/** The dollar value of an amount of credits. `usdPerCredit` defaults to {@link DEFAULT_USD_PER_CREDIT}. */\nexport function creditsToUsd(\n credits: number,\n usdPerCredit: number = DEFAULT_USD_PER_CREDIT\n): number {\n return credits * usdPerCredit\n}\n\n/** The slice of a usage response that tells whether anything was recorded. */\nexport interface UsageTotals {\n total_spend: number\n total_tokens: number\n total_requests: number\n}\n\n/**\n * Was this usage actually metered? A `dev`-plan project with an all-zero response (no spend, no\n * tokens, no requests) is treated as \"not metered\", so the UI shows a note instead of silent\n * zeros. Any recorded tokens or requests mean usage was metered, even when the spend rounds to 0\n * (the backend now records usage when billing is off, and a tiny spend can be 0.00 credits).\n */\nexport function isUsageMetered(\n usage: UsageTotals,\n subscription: string | null | undefined\n): boolean {\n const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0\n return !(empty && subscription === 'dev')\n}\n","/**\n * React Query hooks that use the Arbi instance from context.\n */\n\nimport { useMemo } from 'react'\nimport { useQuery, useQueries, useMutation, useQueryClient } from '@tanstack/react-query'\nimport type {\n SSEStreamResult,\n SSEStreamStartData,\n ResponseOutputItemDoneEvent,\n ArtifactEvent,\n UserMessageEvent,\n MessageMetadataPayload,\n QueryOptions,\n} from '@arbidocs/sdk/browser'\nimport { useArbi } from './useArbi'\nimport type { ParsedDocument } from './documents/parsed-types'\nimport { isUsageMetered } from './credits'\n\n// ── Query keys ──────────────────────────────────────────────────────────────\n\nexport const arbiQueryKeys = {\n workspaces: () => ['arbi', 'workspaces'] as const,\n workspaceUsers: (workspaceId: string) => ['arbi', 'workspaceUsers', workspaceId] as const,\n documents: (workspaceId: string) => ['arbi', 'documents', workspaceId] as const,\n conversations: (workspaceId: string) => ['arbi', 'conversations', workspaceId] as const,\n /** Every workspace's conversation list (and threads): the prefix a conversation write invalidates. */\n allConversations: () => ['arbi', 'conversations'] as const,\n conversationThreads: (workspaceId: string, conversationId: string) =>\n ['arbi', 'conversations', workspaceId, 'threads', conversationId] as const,\n tags: (workspaceId: string) => ['arbi', 'tags', workspaceId] as const,\n thumbnails: (docIds: string[]) => ['arbi', 'thumbnails', [...docIds].sort().join(',')] as const,\n parsedDoc: (docId: string, stage: string) => ['arbi', 'parsedDoc', docId, stage] as const,\n agents: () => ['arbi', 'agents'] as const,\n sessions: () => ['arbi', 'sessions'] as const,\n health: () => ['arbi', 'health'] as const,\n workflows: () => ['arbi', 'workflows'] as const,\n facts: (workspaceId: string) => ['arbi', 'facts', workspaceId] as const,\n configs: () => ['arbi', 'configs'] as const,\n activity: () => ['arbi', 'activity'] as const,\n projects: () => ['arbi', 'projects'] as const,\n projectUsage: (projectExtId: string, monthsBack: number) =>\n ['arbi', 'projectUsage', projectExtId, monthsBack] as const,\n projectInvoices: (projectExtId: string) => ['arbi', 'projectInvoices', projectExtId] as const,\n userUsageToday: () => ['arbi', 'userUsageToday'] as const,\n contacts: () => ['arbi', 'contacts'] as const,\n skills: () => ['arbi', 'skills'] as const,\n /** An agent's pinned config; `undefined` = the library default config. */\n agentConfig: (agentExtId?: string) => ['arbi', 'agentConfig', agentExtId ?? 'default'] as const,\n agentWorkspaces: (agentExtId: string) => ['arbi', 'agentWorkspaces', agentExtId] as const,\n models: () => ['arbi', 'models'] as const,\n /** The signed-in user's own profile (name, picture, email). */\n profile: () => ['arbi', 'profile'] as const,\n /** The signed-in user's settings record (notification preferences, flags). */\n userSettings: () => ['arbi', 'userSettings'] as const,\n}\n\n// ── Hooks ───────────────────────────────────────────────────────────────────\n\n/** Workspace people for mentions, ownership and sign-off. */\nexport function useWorkspaceUsers(\n workspaceId: string | undefined,\n options?: {\n enabled?: boolean\n beforeFetch?: () => Promise<unknown>\n }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.workspaceUsers(workspaceId ?? ''),\n enabled: !!workspaceId && (options?.enabled ?? arbi.hasWorkspace),\n queryFn: async () => {\n await options?.beforeFetch?.()\n if (arbi.getWorkspaceId() !== workspaceId) throw new Error('The selected workspace changed.')\n return arbi.workspaces.listUsers()\n },\n refetchInterval: 30_000,\n })\n}\n\n/** List the logged-in user's workspaces. */\nexport function useWorkspaces(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.workspaces(),\n queryFn: () => arbi.workspaces.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/** List documents in a workspace. */\nexport function useDocuments(workspaceId: string | undefined, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.documents(workspaceId ?? ''),\n queryFn: () => arbi.documents.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n/** List conversations in a workspace. */\nexport function useConversations(\n workspaceId: string | undefined,\n options?: { enabled?: boolean; live?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.conversations(workspaceId ?? ''),\n queryFn: () => arbi.conversations.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n refetchInterval: options?.live\n ? (query) =>\n query.state.data?.some((conversation) => conversation.status === 'generating')\n ? 3000\n : 15000\n : false,\n })\n}\n\n/**\n * A conversation's stored threads (each with its message history, citations data included).\n * Always refetched on mount: a conversation that was open before may have new turns.\n */\nexport function useConversationThreads(\n workspaceId: string | undefined,\n conversationId: string | undefined,\n options?: { enabled?: boolean; live?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.conversationThreads(workspaceId ?? '', conversationId ?? ''),\n queryFn: () => arbi.conversations.getThreads(conversationId as string),\n enabled: (options?.enabled ?? true) && !!workspaceId && !!conversationId && arbi.hasWorkspace,\n gcTime: 0,\n refetchInterval: options?.live ? 3000 : false,\n })\n}\n\n/** List tags in a workspace. */\nexport function useTags(workspaceId: string | undefined, options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.tags(workspaceId ?? ''),\n queryFn: () => arbi.tags.list(),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n/**\n * Batch-fetch first-page thumbnails for a set of documents. Returns a map of\n * doc external id → `data:image/webp` URI (or `null` when no thumbnail exists).\n * Cached for a few minutes since thumbnails are effectively immutable per doc.\n */\nexport function useThumbnails(docIds: string[], options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.thumbnails(docIds),\n queryFn: () => arbi.documents.getThumbnails(docIds),\n enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.hasWorkspace,\n staleTime: 5 * 60_000,\n })\n}\n\n/**\n * Fetch a document's parsed content (chunks grouped by page) for the review\n * viewer. `stage` defaults to `final` (fully processed); `marker`/`subchunk`\n * expose earlier pipeline stages.\n */\nexport function useParsedDocument(\n docId: string | undefined,\n stage: string = 'final',\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.parsedDoc(docId ?? '', stage),\n queryFn: () =>\n arbi.documents.getParsedContent(docId as string, stage) as unknown as Promise<ParsedDocument>,\n enabled: (options?.enabled ?? true) && !!docId && arbi.hasWorkspace,\n })\n}\n\n/** Send a streaming query to the RAG assistant. Returns a mutation. */\nexport function useAssistantQuery() {\n const arbi = useArbi()\n\n return useMutation<\n SSEStreamResult,\n Error,\n {\n question: string\n agentId?: string\n workspaceId?: string\n activeArtifactExtId?: string\n docIds: string[]\n previousResponseId?: string | null\n conversationId?: string\n assistantMode?: QueryOptions['assistantMode']\n mentions?: QueryOptions['mentions']\n model?: string\n onToken?: (content: string) => void\n /** Aborts the request and the stream; the mutation then rejects with an `AbortError`. */\n signal?: AbortSignal\n onStreamStart?: (data: SSEStreamStartData) => void\n onUserMessage?: (data: UserMessageEvent) => void\n onMetadata?: (data: MessageMetadataPayload) => void\n onOutputItemDone?: (data: ResponseOutputItemDoneEvent) => void\n onArtifact?: (data: ArtifactEvent) => void\n onError?: (message: string) => void\n onComplete?: () => void\n }\n >({\n mutationFn: ({ question, ...options }) => arbi.assistant.query(question, options),\n })\n}\n\n/** List agents owned by the current user. */\nexport function useAgents(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.agents(),\n queryFn: () => arbi.agents.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/**\n * Delete agents. Returns a mutation. Refreshes the agent list, the workflow list and the conversation list\n * (a deleted agent's workflows and work go with it), and drops the deleted agents' own config and workspace queries.\n */\nexport function useDeleteAgents() {\n const arbi = useArbi()\n const qc = useQueryClient()\n return useMutation<unknown, Error, { agentExtIds: string[] }>({\n mutationFn: ({ agentExtIds }) => arbi.agents.delete(agentExtIds),\n onSuccess: (_result, { agentExtIds }) => {\n for (const id of agentExtIds) {\n qc.removeQueries({ queryKey: arbiQueryKeys.agentConfig(id) })\n qc.removeQueries({ queryKey: arbiQueryKeys.agentWorkspaces(id) })\n }\n return Promise.all([\n qc.invalidateQueries({ queryKey: arbiQueryKeys.agents() }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.workflows() }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.allConversations() }),\n qc.invalidateQueries({ queryKey: arbiQueryKeys.configs() }),\n ])\n },\n })\n}\n\n/** List active sessions. */\nexport function useSessions(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.sessions(),\n queryFn: () => arbi.sessions.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/** Authorize a delegated session (generates claim code). Returns a mutation. */\n\n/** Check backend health. */\nexport function useHealth(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.health(),\n queryFn: () => arbi.health.check(),\n enabled: options?.enabled,\n })\n}\n\n// ── Workspace notes ──────────────────────────────────────────────────────────\n\n/** List the open workspace's facts. */\nexport function useFacts(\n workspaceId: string | undefined,\n options?: { enabled?: boolean; pinnedOnly?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.facts(workspaceId ?? ''),\n queryFn: () => arbi.facts.list({ pinnedOnly: options?.pinnedOnly }),\n enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace,\n })\n}\n\n// ── Behaviour-template configs ───────────────────────────────────────────────\n\n/** List the caller's saved agent configurations (behaviour templates). */\nexport function useConfigs(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.configs(),\n queryFn: () => arbi.agentConfig.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n// ── Activity feed ─────────────────────────────────────────────────────────────\n\n/**\n * List the caller's durable activity feed, newest first.\n *\n * Activity entries are backend-originated, to-self log lines that are always\n * read — they are deliberately kept out of the normal notifications/DM feed and\n * never affect the unread badge, so this is a separate, opt-in query.\n */\nexport function useActivity(options?: { enabled?: boolean; limit?: number; offset?: number }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.activity(),\n queryFn: () => arbi.dm.listActivity({ limit: options?.limit, offset: options?.offset }),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n// ── Projects, usage & spend ───────────────────────────────────────────────────\n\n/** List the logged-in user's projects (billing accounts). */\nexport function useProjects(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.projects(),\n queryFn: () => arbi.projects.list(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n\n/**\n * AI usage breakdown for a project's billing period. `monthsBack` selects the period (0 =\n * current, 1 = previous month, …).\n *\n * The response's `total_spend` / `spend` fields are CREDITS, not dollars (see `formatCredits`).\n * `metered` is `false` when the deployment does not record usage (a `dev`-plan project with all\n * zeros): show \"usage is not metered here\" instead of zeros. It is `undefined` until the usage\n * has loaded.\n */\nexport function useProjectUsage(\n projectExtId: string | undefined,\n monthsBack: number = 0,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n const usage = useQuery({\n queryKey: arbiQueryKeys.projectUsage(projectExtId ?? '', monthsBack),\n queryFn: () => arbi.projects.usage(projectExtId as string, monthsBack),\n enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn,\n })\n const projects = useProjects({ enabled: !!projectExtId && (options?.enabled ?? true) })\n const subscription = projects.data?.find((p) => p.external_id === projectExtId)?.subscription\n const metered = usage.data ? isUsageMetered(usage.data, subscription) : undefined\n return { ...usage, metered }\n}\n\n/** One day of aggregated usage across projects (for a spend/token trend). */\nexport interface AggregatedDailyUsage {\n date: string\n /** Credits used that day (not dollars). */\n credits: number\n totalTokens: number\n apiRequests: number\n}\n\n/** One model group's aggregated usage across projects (for a breakdown). */\nexport interface AggregatedModelGroupUsage {\n model: string\n /** Credits used by this model group (not dollars). */\n credits: number\n totalTokens: number\n promptTokens: number\n completionTokens: number\n successfulRequests: number\n}\n\n/** Aggregated AI usage + spend across several projects. */\nexport interface ProjectsUsageAggregate {\n /** Summed usage across the projects, in CREDITS (1 credit = $0.01 by default), not dollars. */\n totalCredits: number\n /** Summed token count across the projects. */\n totalTokens: number\n /** Summed API request count across the projects. */\n totalRequests: number\n /** Per-day totals merged across every project, oldest first. */\n daily: AggregatedDailyUsage[]\n /** Per-model-group totals merged across every project, most credits first. */\n modelGroups: AggregatedModelGroupUsage[]\n /**\n * False when none of the loaded projects records usage (billing is off on this deployment), so\n * zeros mean \"not metered\". True while anything real was recorded, or before data arrived.\n */\n metered: boolean\n /** True while any per-project query is still loading. */\n isLoading: boolean\n /** True if any per-project query errored. */\n isError: boolean\n}\n\n/**\n * Firm-wide AI usage + spend: aggregates {@link useProjectUsage} across several\n * projects (e.g. all of a firm's matters) in parallel and merges the real totals,\n * the daily trend, and the per-model breakdown. Shares the per-project query\n * cache, so it costs nothing extra where a project's usage is already loaded.\n * Numbers are genuine — zero projects (or zero billed work) yields zero totals;\n * callers render that honestly.\n */\nexport function useProjectsUsage(\n projectExtIds: string[],\n monthsBack: number = 0,\n options?: { enabled?: boolean }\n): ProjectsUsageAggregate {\n const arbi = useArbi()\n const enabled = (options?.enabled ?? true) && arbi.isLoggedIn\n const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 })\n const results = useQueries({\n queries: projectExtIds.map((id) => ({\n queryKey: arbiQueryKeys.projectUsage(id, monthsBack),\n queryFn: () => arbi.projects.usage(id, monthsBack),\n enabled: enabled && !!id,\n })),\n })\n\n // Recompute only when a query's data actually changes (not on every parent\n // render — the dashboard re-renders often while a digest streams).\n const signature =\n results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join('|') +\n `#${projects.dataUpdatedAt}`\n\n return useMemo(() => {\n const dailyMap = new Map<string, AggregatedDailyUsage>()\n const modelMap = new Map<string, AggregatedModelGroupUsage>()\n let totalCredits = 0\n let anyData = false\n let anyMetered = false\n let totalTokens = 0\n let totalRequests = 0\n\n results.forEach((r, i) => {\n const d = r.data\n if (!d) return\n anyData = true\n const subscription = projects.data?.find(\n (p) => p.external_id === projectExtIds[i]\n )?.subscription\n if (isUsageMetered(d, subscription)) anyMetered = true\n totalCredits += d.total_spend ?? 0\n totalTokens += d.total_tokens ?? 0\n totalRequests += d.total_requests ?? 0\n\n for (const day of d.daily ?? []) {\n const cur = dailyMap.get(day.date) ?? {\n date: day.date,\n credits: 0,\n totalTokens: 0,\n apiRequests: 0,\n }\n cur.credits += day.spend ?? 0\n cur.totalTokens += day.total_tokens ?? 0\n cur.apiRequests += day.api_requests ?? 0\n dailyMap.set(day.date, cur)\n }\n\n for (const [model, mg] of Object.entries(d.model_groups ?? {})) {\n const cur = modelMap.get(model) ?? {\n model,\n credits: 0,\n totalTokens: 0,\n promptTokens: 0,\n completionTokens: 0,\n successfulRequests: 0,\n }\n cur.credits += mg.spend ?? 0\n cur.totalTokens += mg.total_tokens ?? 0\n cur.promptTokens += mg.prompt_tokens ?? 0\n cur.completionTokens += mg.completion_tokens ?? 0\n cur.successfulRequests += mg.successful_requests ?? 0\n modelMap.set(model, cur)\n }\n })\n\n return {\n totalCredits,\n totalTokens,\n totalRequests,\n daily: [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date)),\n modelGroups: [...modelMap.values()].sort(\n (a, b) => b.credits - a.credits || b.totalTokens - a.totalTokens\n ),\n metered: !anyData || anyMetered,\n isLoading: results.some((r) => r.isLoading),\n isError: results.some((r) => r.isError),\n }\n }, [signature])\n}\n\n/** List the Stripe invoices for a project's subscription. */\nexport function useProjectInvoices(\n projectExtId: string | undefined,\n options?: { enabled?: boolean }\n) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ''),\n queryFn: () => arbi.projects.invoices(projectExtId as string),\n enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn,\n })\n}\n\n/** Today's deployment-wide credit use for the current user (`credits_used`, in credits). */\nexport function useUserUsageToday(options?: { enabled?: boolean }) {\n const arbi = useArbi()\n return useQuery({\n queryKey: arbiQueryKeys.userUsageToday(),\n queryFn: () => arbi.user.usageToday(),\n enabled: options?.enabled ?? arbi.isLoggedIn,\n })\n}\n","/**\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"]}