@pixerate/editor 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ import * as _tiptap_core from '@tiptap/core';
2
+ import * as _tiptap_extension_mention from '@tiptap/extension-mention';
3
+ import { MentionOptions as MentionOptions$1 } from '@tiptap/extension-mention';
4
+ import { SuggestionOptions } from '@tiptap/suggestion';
5
+
6
+ interface MentionEntity {
7
+ id: string;
8
+ label: string;
9
+ type?: string;
10
+ avatarUrl?: string;
11
+ color?: string;
12
+ handle?: string;
13
+ name?: string;
14
+ hexColor?: string;
15
+ aliases?: string[];
16
+ [key: string]: any;
17
+ }
18
+ interface MentionOptions extends Partial<MentionOptions$1> {
19
+ HTMLAttributes?: Record<string, any>;
20
+ suggestion?: Partial<SuggestionOptions<MentionEntity>>;
21
+ }
22
+ /**
23
+ * First-class native Mention extension for @pixerate/editor.
24
+ * Creates atomic inline <span data-type="mention"> nodes with full suggestion support.
25
+ */
26
+ declare const Mention: _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
27
+ /**
28
+ * Helper to configure the Mention extension with preset defaults.
29
+ */
30
+ declare function createMentionExtension(options?: Partial<MentionOptions>): _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
31
+
32
+ export { Mention as M, type MentionEntity as a, type MentionOptions as b, createMentionExtension as c };
@@ -0,0 +1,32 @@
1
+ import * as _tiptap_core from '@tiptap/core';
2
+ import * as _tiptap_extension_mention from '@tiptap/extension-mention';
3
+ import { MentionOptions as MentionOptions$1 } from '@tiptap/extension-mention';
4
+ import { SuggestionOptions } from '@tiptap/suggestion';
5
+
6
+ interface MentionEntity {
7
+ id: string;
8
+ label: string;
9
+ type?: string;
10
+ avatarUrl?: string;
11
+ color?: string;
12
+ handle?: string;
13
+ name?: string;
14
+ hexColor?: string;
15
+ aliases?: string[];
16
+ [key: string]: any;
17
+ }
18
+ interface MentionOptions extends Partial<MentionOptions$1> {
19
+ HTMLAttributes?: Record<string, any>;
20
+ suggestion?: Partial<SuggestionOptions<MentionEntity>>;
21
+ }
22
+ /**
23
+ * First-class native Mention extension for @pixerate/editor.
24
+ * Creates atomic inline <span data-type="mention"> nodes with full suggestion support.
25
+ */
26
+ declare const Mention: _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
27
+ /**
28
+ * Helper to configure the Mention extension with preset defaults.
29
+ */
30
+ declare function createMentionExtension(options?: Partial<MentionOptions>): _tiptap_core.Node<MentionOptions$1<any, _tiptap_extension_mention.MentionNodeAttrs>, any>;
31
+
32
+ export { Mention as M, type MentionEntity as a, type MentionOptions as b, createMentionExtension as c };
@@ -30,16 +30,167 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/serializers/index.ts
31
31
  var serializers_exports = {};
32
32
  __export(serializers_exports, {
33
+ MARKDOWN_MENTION_SPLIT_REGEX: () => MARKDOWN_MENTION_SPLIT_REGEX,
34
+ MENTION_REGEX: () => MENTION_REGEX,
33
35
  escapeHtml: () => escapeHtml,
36
+ extractMentions: () => extractMentions,
34
37
  extractMentionsFromDoc: () => extractMentionsFromDoc,
35
38
  getEditorMarkdown: () => getEditorMarkdown,
36
39
  getEditorText: () => getEditorText,
37
40
  htmlToPlainText: () => htmlToPlainText,
38
41
  markdownToTipTapHtml: () => markdownToTipTapHtml,
39
- plainTextToTipTapHtml: () => plainTextToTipTapHtml
42
+ parseMentionSegments: () => parseMentionSegments,
43
+ plainTextToTipTapHtml: () => plainTextToTipTapHtml,
44
+ preprocessMarkdownFileLinks: () => preprocessMarkdownFileLinks,
45
+ preprocessMarkdownMentions: () => preprocessMarkdownMentions,
46
+ stripMarkdownCode: () => stripMarkdownCode
40
47
  });
41
48
  module.exports = __toCommonJS(serializers_exports);
42
49
 
50
+ // src/serializers/mentions.ts
51
+ var MENTION_REGEX = /(?:^|[\s>(*_"';\\/[\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:"([^"]+)"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*))/g;
52
+ var MARKDOWN_MENTION_SPLIT_REGEX = /(```[\s\S]*?```|~~~[\s\S]*?~~~|<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>|`[^`\n]+`|<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])[^>]*>[\s\S]*?<\/span>|<[^>]+>|\]\([^)]+\)|(?:https?|file|vscode|cursor|mailto):\/\/[^\s<)]+)/gi;
53
+ function stripMarkdownCode(content) {
54
+ if (!content || typeof content !== "string") return "";
55
+ return content.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "").replace(/<pre[\s\S]*?<\/pre>/gi, "").replace(/<code[\s\S]*?<\/code>/gi, "").replace(/`[^`\n]*`/g, "");
56
+ }
57
+ function extractMentions(content) {
58
+ if (!content || typeof content !== "string") return [];
59
+ const normalizedMentionNodes = content.replace(
60
+ /<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["'])[^>]*>([\s\S]*?)<\/span>/gi,
61
+ (match2, inner) => {
62
+ const labelMatch = match2.match(/\bdata-label=["']([^"']+)["']/i);
63
+ if (labelMatch) return ` @${labelMatch[1]} `;
64
+ const idMatch = match2.match(/\bdata-id=["']([^"']+)["']/i);
65
+ if (idMatch) return ` @${idMatch[1]} `;
66
+ return ` ${inner} `;
67
+ }
68
+ );
69
+ const cleanContent = stripMarkdownCode(normalizedMentionNodes);
70
+ const withoutUrls = cleanContent.replace(/(?:https?|ftp|file|vscode|cursor|mailto):\/\/[^\s<>()]+/gi, "").replace(/\]\([^)]*\)/g, "]");
71
+ const textOnly = withoutUrls.replace(/<[^>]+>/g, " ");
72
+ const mentions = [];
73
+ const seen = /* @__PURE__ */ new Set();
74
+ const regex = new RegExp(MENTION_REGEX.source, "g");
75
+ let match;
76
+ while ((match = regex.exec(textOnly)) !== null) {
77
+ const handle = (match[1] ?? match[2] ?? match[3] ?? "").trim();
78
+ if (handle && !seen.has(handle)) {
79
+ seen.add(handle);
80
+ mentions.push(handle);
81
+ }
82
+ }
83
+ return mentions;
84
+ }
85
+ function parseMentionSegments(content) {
86
+ if (!content) return [];
87
+ const segments = [];
88
+ const regex = new RegExp(MENTION_REGEX.source, "g");
89
+ let lastIndex = 0;
90
+ let match;
91
+ while ((match = regex.exec(content)) !== null) {
92
+ const fullMatch = match[0];
93
+ const atIndex = fullMatch.indexOf("@");
94
+ const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : "";
95
+ const mentionToken = fullMatch.slice(atIndex);
96
+ const handle = match[1] ?? match[2] ?? match[3];
97
+ const matchStart = match.index + prefix.length;
98
+ if (matchStart > lastIndex) {
99
+ segments.push({
100
+ type: "text",
101
+ value: content.slice(lastIndex, matchStart)
102
+ });
103
+ }
104
+ segments.push({
105
+ type: "mention",
106
+ value: mentionToken,
107
+ handle
108
+ });
109
+ lastIndex = matchStart + mentionToken.length;
110
+ }
111
+ if (lastIndex < content.length) {
112
+ segments.push({
113
+ type: "text",
114
+ value: content.slice(lastIndex)
115
+ });
116
+ }
117
+ return segments;
118
+ }
119
+ function preprocessMarkdownMentions(content, optionsOrMentionables = []) {
120
+ if (!content || typeof content !== "string") return "";
121
+ const options = Array.isArray(optionsOrMentionables) ? { mentionables: optionsOrMentionables } : optionsOrMentionables;
122
+ const allMentionables = options.mentionables || [];
123
+ const defaultType = options.defaultType || "user";
124
+ const resolveMention = options.resolveMention;
125
+ const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);
126
+ return parts.map((part) => {
127
+ if (!part) return "";
128
+ if (part.startsWith("```") || part.startsWith("~~~") || part.startsWith("`") || part.startsWith("](") || /^(?:https?|file|vscode|cursor|mailto):\/\//i.test(part) || /^<pre[\s>]/i.test(part) || /^<code[\s>]/i.test(part) || /^<[^>]+>$/i.test(part) || /^<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])/i.test(
129
+ part
130
+ )) {
131
+ return part;
132
+ }
133
+ const regex = new RegExp(MENTION_REGEX.source, "g");
134
+ return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {
135
+ const atIndex = match.indexOf("@");
136
+ const prefix = atIndex > 0 ? match.slice(0, atIndex) : "";
137
+ const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || "").trim();
138
+ if (!rawHandle) return match;
139
+ const lowerHandle = rawHandle.toLowerCase();
140
+ const entity = allMentionables.find((e) => {
141
+ if (e.label?.toLowerCase() === lowerHandle) return true;
142
+ if (e.handle?.toLowerCase() === lowerHandle) return true;
143
+ if (e.name?.toLowerCase() === lowerHandle) return true;
144
+ if (e.id?.toLowerCase() === lowerHandle) return true;
145
+ if (e.type === "agent" && `agent${(e.handle || e.label || "").toLowerCase()}` === lowerHandle) return true;
146
+ if (e.aliases?.some(
147
+ (a) => a.toLowerCase() === lowerHandle || e.type === "agent" && `agent${a.toLowerCase()}` === lowerHandle
148
+ )) {
149
+ return true;
150
+ }
151
+ return false;
152
+ });
153
+ let id = entity?.id;
154
+ let label = entity?.label || entity?.handle || rawHandle;
155
+ let type = entity?.type;
156
+ let avatarUrl = entity?.avatarUrl;
157
+ let color = entity?.color || entity?.hexColor;
158
+ if (!entity) {
159
+ const customResolved = resolveMention?.(rawHandle);
160
+ if (customResolved) {
161
+ id = customResolved.id ?? id;
162
+ label = customResolved.label ?? customResolved.handle ?? label;
163
+ type = customResolved.type ?? type;
164
+ avatarUrl = customResolved.avatarUrl ?? avatarUrl;
165
+ color = customResolved.color ?? customResolved.hexColor ?? color;
166
+ } else {
167
+ const stripped = lowerHandle.replace(/^agent[\s\-_]*/i, "");
168
+ if (["supervisor", "coordinator", "planner", "validator", "executor"].includes(stripped)) {
169
+ type = "agent";
170
+ id = stripped;
171
+ label = stripped;
172
+ } else if (lowerHandle === "agents") {
173
+ type = "team";
174
+ id = "agents";
175
+ label = "agents";
176
+ } else {
177
+ type = defaultType;
178
+ id = rawHandle;
179
+ label = rawHandle;
180
+ }
181
+ }
182
+ }
183
+ const avatarAttr = avatarUrl ? ` data-avatar-url="${escapeHtml(avatarUrl)}"` : "";
184
+ const colorAttr = color ? ` data-color="${escapeHtml(color)}"` : "";
185
+ return `${prefix}<span class="pixerate-mention-node" data-type="mention" data-id="${escapeHtml(
186
+ id || label
187
+ )}" data-label="${escapeHtml(label)}" data-mention-suggestion-char="@" data-type-name="${escapeHtml(
188
+ type || defaultType
189
+ )}"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;
190
+ });
191
+ }).join("");
192
+ }
193
+
43
194
  // src/serializers/plain-text.ts
44
195
  function escapeHtml(text) {
45
196
  if (!text) return "";
@@ -164,6 +315,16 @@ function extractMentionsFromDoc(docOrEditor) {
164
315
  });
165
316
  }
166
317
  }
318
+ if (mentions.length === 0) {
319
+ const rawHandles = extractMentions(docOrEditor);
320
+ for (const handle of rawHandles) {
321
+ mentions.push({
322
+ id: handle,
323
+ label: handle,
324
+ type: "user"
325
+ });
326
+ }
327
+ }
167
328
  }
168
329
  return mentions;
169
330
  }
@@ -183,9 +344,31 @@ md.validateLink = (url) => {
183
344
  }
184
345
  return defaultValidateLink.call(md, url);
185
346
  };
186
- function markdownToTipTapHtml(markdown) {
347
+ function preprocessMarkdownFileLinks(content) {
348
+ if (!content) return "";
349
+ return content.replace(
350
+ /\[([^\]]+)\]\(((?:file|vscode|cursor):\/\/[^)]+)\)/g,
351
+ (_match, rawLabel, href) => {
352
+ const trimmed = rawLabel.trim();
353
+ const codeMatch = trimmed.match(/^`([^`]+)`$/);
354
+ const labelContent = codeMatch ? `<code>${codeMatch[1]}</code>` : trimmed;
355
+ return `<a href="${href}" data-file-link="true" title="Click to copy file path">${labelContent}</a>`;
356
+ }
357
+ );
358
+ }
359
+ function markdownToTipTapHtml(markdown, options) {
187
360
  if (!markdown) return "<p></p>";
188
- return md.render(markdown);
361
+ let content = markdown;
362
+ if (options?.preprocessFileLinks) {
363
+ content = preprocessMarkdownFileLinks(content);
364
+ }
365
+ if (options?.preprocessMentions || options?.mentionables || options?.preprocessOptions) {
366
+ const mentionOpts = options.preprocessOptions || {
367
+ mentionables: options.mentionables
368
+ };
369
+ content = preprocessMarkdownMentions(content, mentionOpts);
370
+ }
371
+ return md.render(content);
189
372
  }
190
373
  function getEditorMarkdown(editor) {
191
374
  if (!editor) return "";
@@ -196,12 +379,19 @@ function getEditorMarkdown(editor) {
196
379
  }
197
380
  // Annotate the CommonJS export names for ESM import in node:
198
381
  0 && (module.exports = {
382
+ MARKDOWN_MENTION_SPLIT_REGEX,
383
+ MENTION_REGEX,
199
384
  escapeHtml,
385
+ extractMentions,
200
386
  extractMentionsFromDoc,
201
387
  getEditorMarkdown,
202
388
  getEditorText,
203
389
  htmlToPlainText,
204
390
  markdownToTipTapHtml,
205
- plainTextToTipTapHtml
391
+ parseMentionSegments,
392
+ plainTextToTipTapHtml,
393
+ preprocessMarkdownFileLinks,
394
+ preprocessMarkdownMentions,
395
+ stripMarkdownCode
206
396
  });
207
397
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/serializers/index.ts","../../src/serializers/plain-text.ts","../../src/serializers/markdown.ts"],"sourcesContent":["export * from \"./plain-text\";\nexport * from \"./markdown\";\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n */\nexport function markdownToTipTapHtml(markdown: string): string {\n if (!markdown) return \"<p></p>\";\n return md.render(markdown);\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":"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","names":["MarkdownIt","taskLists"]}
1
+ {"version":3,"sources":["../../src/serializers/index.ts","../../src/serializers/mentions.ts","../../src/serializers/plain-text.ts","../../src/serializers/markdown.ts"],"sourcesContent":["export * from \"./plain-text\";\nexport * from \"./markdown\";\nexport * from \"./mentions\";\n","import { escapeHtml } from \"./plain-text\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Canonical regex pattern for matching @mentions in plain text or markdown.\n * Supports:\n * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1\n * - Quoted handles: @\"John Doe\", &quot;Jane Doe&quot;\n * Unquoted handles exclude trailing punctuation (e.g. @violet. matches \"violet\" without the dot).\n */\nexport const MENTION_REGEX =\n /(?:^|[\\s>(*_\"';\\\\/[\\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:\"([^\"]+)\"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\\.[a-zA-Z0-9_-]+)*))/g;\n\n/**\n * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.\n * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.\n */\nexport const MARKDOWN_MENTION_SPLIT_REGEX =\n /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|<pre[\\s\\S]*?<\\/pre>|<code[\\s\\S]*?<\\/code>|`[^`\\n]+`|<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])[^>]*>[\\s\\S]*?<\\/span>|<[^>]+>|\\]\\([^)]+\\)|(?:https?|file|vscode|cursor|mailto):\\/\\/[^\\s<)]+)/gi;\n\nexport interface MentionSegment {\n type: \"text\" | \"mention\";\n value: string;\n handle?: string;\n}\n\nexport interface PreprocessMarkdownMentionsOptions {\n /**\n * Known pool of mentionable entities (users, agents, teams, etc.).\n */\n mentionables?: MentionEntity[];\n /**\n * Default entity type assigned when a handle does not match any entry in mentionables.\n * Defaults to 'user'.\n */\n defaultType?: string;\n /**\n * Custom resolver callback to derive entity metadata for unmatched handles.\n */\n resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;\n}\n\n/**\n * Strips code blocks and inline code from markdown or HTML content:\n * - Fenced code blocks: ```...``` and ~~~...~~~\n * - Inline backtick code: `...`\n * - HTML code/pre tags: <pre>...</pre>, <code>...</code>\n * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.\n */\nexport function stripMarkdownCode(content: string): string {\n if (!content || typeof content !== \"string\") return \"\";\n return content\n .replace(/```[\\s\\S]*?```/g, \"\")\n .replace(/~~~[\\s\\S]*?~~~/g, \"\")\n .replace(/<pre[\\s\\S]*?<\\/pre>/gi, \"\")\n .replace(/<code[\\s\\S]*?<\\/code>/gi, \"\")\n .replace(/`[^`\\n]*`/g, \"\");\n}\n\n/**\n * Extracts unique mention handles from a text, markdown, or HTML string,\n * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.\n */\nexport function extractMentions(content: string): string[] {\n if (!content || typeof content !== \"string\") return [];\n\n // Normalize existing HTML mention nodes (e.g. from TipTap or rich text serializers)\n // so data-mention-suggestion-char=\"@\" does not trigger spurious quoted matches against attributes,\n // and ensure the actual mentioned label or ID is preserved cleanly.\n const normalizedMentionNodes = content.replace(\n /<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"'])[^>]*>([\\s\\S]*?)<\\/span>/gi,\n (match, inner) => {\n const labelMatch = match.match(/\\bdata-label=[\"']([^\"']+)[\"']/i);\n if (labelMatch) return ` @${labelMatch[1]} `;\n const idMatch = match.match(/\\bdata-id=[\"']([^\"']+)[\"']/i);\n if (idMatch) return ` @${idMatch[1]} `;\n return ` ${inner} `;\n }\n );\n\n const cleanContent = stripMarkdownCode(normalizedMentionNodes);\n // Strip URLs and markdown link destinations so @package or @handles in URLs are not extracted as mentions\n const withoutUrls = cleanContent\n .replace(/(?:https?|ftp|file|vscode|cursor|mailto):\\/\\/[^\\s<>()]+/gi, \"\")\n .replace(/\\]\\([^)]*\\)/g, \"]\");\n // Strip remaining HTML tags so attributes containing '@' or '>' aren't treated as mention triggers\n const textOnly = withoutUrls.replace(/<[^>]+>/g, \" \");\n\n const mentions: string[] = [];\n const seen = new Set<string>();\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(textOnly)) !== null) {\n const handle = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n if (handle && !seen.has(handle)) {\n seen.add(handle);\n mentions.push(handle);\n }\n }\n\n return mentions;\n}\n\n/**\n * Segments a text string into plain text parts and mention tokens.\n * Correctly leaves trailing punctuation (like \".\") as part of the following text segment.\n */\nexport function parseMentionSegments(content: string): MentionSegment[] {\n if (!content) return [];\n\n const segments: MentionSegment[] = [];\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const fullMatch = match[0];\n const atIndex = fullMatch.indexOf(\"@\");\n const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : \"\";\n const mentionToken = fullMatch.slice(atIndex);\n const handle = match[1] ?? match[2] ?? match[3];\n const matchStart = match.index + prefix.length;\n\n if (matchStart > lastIndex) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex, matchStart),\n });\n }\n\n segments.push({\n type: \"mention\",\n value: mentionToken,\n handle,\n });\n\n lastIndex = matchStart + mentionToken.length;\n }\n\n if (lastIndex < content.length) {\n segments.push({\n type: \"text\",\n value: content.slice(lastIndex),\n });\n }\n\n return segments;\n}\n\n/**\n * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible\n * mention HTML spans (<span class=\"pixerate-mention-node\" data-type=\"mention\" ...>),\n * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.\n */\nexport function preprocessMarkdownMentions(\n content: string,\n optionsOrMentionables: MentionEntity[] | PreprocessMarkdownMentionsOptions = []\n): string {\n if (!content || typeof content !== \"string\") return \"\";\n\n const options: PreprocessMarkdownMentionsOptions = Array.isArray(optionsOrMentionables)\n ? { mentionables: optionsOrMentionables }\n : optionsOrMentionables;\n\n const allMentionables = options.mentionables || [];\n const defaultType = options.defaultType || \"user\";\n const resolveMention = options.resolveMention;\n\n const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);\n\n return parts\n .map((part) => {\n if (!part) return \"\";\n\n // Preserve code fences, code tags, inline backticks, existing mention spans,\n // HTML tags, markdown link targets, and raw URLs untouched.\n if (\n part.startsWith(\"```\") ||\n part.startsWith(\"~~~\") ||\n part.startsWith(\"`\") ||\n part.startsWith(\"](\") ||\n /^(?:https?|file|vscode|cursor|mailto):\\/\\//i.test(part) ||\n /^<pre[\\s>]/i.test(part) ||\n /^<code[\\s>]/i.test(part) ||\n /^<[^>]+>$/i.test(part) ||\n /^<span\\b[^>]*\\b(?:data-type=[\"']mention[\"']|class=[\"'][^\"']*pixerate-mention-node[^\"']*[\"']|data-mention=[\"'][^\"']*[\"'])/i.test(\n part\n )\n ) {\n return part;\n }\n\n const regex = new RegExp(MENTION_REGEX.source, \"g\");\n return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {\n const atIndex = match.indexOf(\"@\");\n const prefix = atIndex > 0 ? match.slice(0, atIndex) : \"\";\n const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || \"\").trim();\n if (!rawHandle) return match;\n\n const lowerHandle = rawHandle.toLowerCase();\n const entity = allMentionables.find((e) => {\n if (e.label?.toLowerCase() === lowerHandle) return true;\n if (e.handle?.toLowerCase() === lowerHandle) return true;\n if (e.name?.toLowerCase() === lowerHandle) return true;\n if (e.id?.toLowerCase() === lowerHandle) return true;\n if (e.type === \"agent\" && `agent${(e.handle || e.label || \"\").toLowerCase()}` === lowerHandle) return true;\n if (\n e.aliases?.some(\n (a: string) =>\n a.toLowerCase() === lowerHandle ||\n (e.type === \"agent\" && `agent${a.toLowerCase()}` === lowerHandle)\n )\n ) {\n return true;\n }\n return false;\n });\n\n let id = entity?.id;\n let label = entity?.label || entity?.handle || rawHandle;\n let type = entity?.type;\n let avatarUrl = entity?.avatarUrl;\n let color = entity?.color || entity?.hexColor;\n\n if (!entity) {\n const customResolved = resolveMention?.(rawHandle);\n if (customResolved) {\n id = customResolved.id ?? id;\n label = customResolved.label ?? customResolved.handle ?? label;\n type = customResolved.type ?? type;\n avatarUrl = customResolved.avatarUrl ?? avatarUrl;\n color = customResolved.color ?? customResolved.hexColor ?? color;\n } else {\n const stripped = lowerHandle.replace(/^agent[\\s\\-_]*/i, \"\");\n if (\n [\"supervisor\", \"coordinator\", \"planner\", \"validator\", \"executor\"].includes(stripped)\n ) {\n type = \"agent\";\n id = stripped;\n label = stripped;\n } else if (lowerHandle === \"agents\") {\n type = \"team\";\n id = \"agents\";\n label = \"agents\";\n } else {\n type = defaultType;\n id = rawHandle;\n label = rawHandle;\n }\n }\n }\n\n const avatarAttr = avatarUrl ? ` data-avatar-url=\"${escapeHtml(avatarUrl)}\"` : \"\";\n const colorAttr = color ? ` data-color=\"${escapeHtml(color)}\"` : \"\";\n\n return `${prefix}<span class=\"pixerate-mention-node\" data-type=\"mention\" data-id=\"${escapeHtml(\n id || label\n )}\" data-label=\"${escapeHtml(label)}\" data-mention-suggestion-char=\"@\" data-type-name=\"${escapeHtml(\n type || defaultType\n )}\"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;\n });\n })\n .join(\"\");\n}\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\nimport { extractMentions } from \"./mentions\";\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n\n // Fallback: If no HTML mention tags were found, extract raw @mentions from text or markdown\n if (mentions.length === 0) {\n const rawHandles = extractMentions(docOrEditor);\n for (const handle of rawHandles) {\n mentions.push({\n id: handle,\n label: handle,\n type: \"user\",\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\nconst defaultValidateLink = md.validateLink;\nmd.validateLink = (url: string) => {\n if (\n url.startsWith(\"file://\") ||\n url.startsWith(\"vscode://\") ||\n url.startsWith(\"cursor://\")\n ) {\n return true;\n }\n return defaultValidateLink.call(md, url);\n};\n\nimport {\n preprocessMarkdownMentions,\n type PreprocessMarkdownMentionsOptions,\n} from \"./mentions\";\nimport type { MentionEntity } from \"../extensions/mention\";\n\n/**\n * Preprocesses file-protocol and editor-protocol links in markdown content:\n * converts [label](file://...), vscode://, and cursor:// links into anchor tags\n * annotated with data-file-link=\"true\", preserving code backticks in labels.\n */\nexport function preprocessMarkdownFileLinks(content: string): string {\n if (!content) return \"\";\n return content.replace(\n /\\[([^\\]]+)\\]\\(((?:file|vscode|cursor):\\/\\/[^)]+)\\)/g,\n (_match, rawLabel, href) => {\n const trimmed = rawLabel.trim();\n const codeMatch = trimmed.match(/^`([^`]+)`$/);\n const labelContent = codeMatch ? `<code>${codeMatch[1]}</code>` : trimmed;\n return `<a href=\"${href}\" data-file-link=\"true\" title=\"Click to copy file path\">${labelContent}</a>`;\n }\n );\n}\n\nexport interface MarkdownToHtmlOptions {\n /**\n * Preprocess file, vscode, and cursor links into clickable data-file-link tags.\n */\n preprocessFileLinks?: boolean;\n /**\n * Whether to preprocess @mentions into TipTap mention node HTML spans.\n */\n preprocessMentions?: boolean;\n /**\n * Pool of mentionables to pass to preprocessMarkdownMentions.\n */\n mentionables?: MentionEntity[];\n /**\n * Full options for preprocessMarkdownMentions.\n */\n preprocessOptions?: PreprocessMarkdownMentionsOptions;\n}\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n */\nexport function markdownToTipTapHtml(\n markdown: string,\n options?: MarkdownToHtmlOptions\n): string {\n if (!markdown) return \"<p></p>\";\n let content = markdown;\n if (options?.preprocessFileLinks) {\n content = preprocessMarkdownFileLinks(content);\n }\n if (\n options?.preprocessMentions ||\n options?.mentionables ||\n options?.preprocessOptions\n ) {\n const mentionOpts = options.preprocessOptions || {\n mentionables: options.mentionables,\n };\n content = preprocessMarkdownMentions(content, mentionOpts);\n }\n return md.render(content);\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":"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","names":["match","MarkdownIt","taskLists"]}
@@ -1,3 +1,8 @@
1
+ import { a as MentionEntity } from '../mention-Dcevh3ff.cjs';
2
+ import '@tiptap/core';
3
+ import '@tiptap/extension-mention';
4
+ import '@tiptap/suggestion';
5
+
1
6
  /**
2
7
  * Escapes characters that have syntactic meaning in HTML text.
3
8
  */
@@ -30,10 +35,92 @@ interface ExtractedMention {
30
35
  */
31
36
  declare function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[];
32
37
 
38
+ /**
39
+ * Canonical regex pattern for matching @mentions in plain text or markdown.
40
+ * Supports:
41
+ * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1
42
+ * - Quoted handles: @"John Doe", &quot;Jane Doe&quot;
43
+ * Unquoted handles exclude trailing punctuation (e.g. @violet. matches "violet" without the dot).
44
+ */
45
+ declare const MENTION_REGEX: RegExp;
46
+ /**
47
+ * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.
48
+ * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.
49
+ */
50
+ declare const MARKDOWN_MENTION_SPLIT_REGEX: RegExp;
51
+ interface MentionSegment {
52
+ type: "text" | "mention";
53
+ value: string;
54
+ handle?: string;
55
+ }
56
+ interface PreprocessMarkdownMentionsOptions {
57
+ /**
58
+ * Known pool of mentionable entities (users, agents, teams, etc.).
59
+ */
60
+ mentionables?: MentionEntity[];
61
+ /**
62
+ * Default entity type assigned when a handle does not match any entry in mentionables.
63
+ * Defaults to 'user'.
64
+ */
65
+ defaultType?: string;
66
+ /**
67
+ * Custom resolver callback to derive entity metadata for unmatched handles.
68
+ */
69
+ resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;
70
+ }
71
+ /**
72
+ * Strips code blocks and inline code from markdown or HTML content:
73
+ * - Fenced code blocks: ```...``` and ~~~...~~~
74
+ * - Inline backtick code: `...`
75
+ * - HTML code/pre tags: <pre>...</pre>, <code>...</code>
76
+ * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.
77
+ */
78
+ declare function stripMarkdownCode(content: string): string;
79
+ /**
80
+ * Extracts unique mention handles from a text, markdown, or HTML string,
81
+ * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.
82
+ */
83
+ declare function extractMentions(content: string): string[];
84
+ /**
85
+ * Segments a text string into plain text parts and mention tokens.
86
+ * Correctly leaves trailing punctuation (like ".") as part of the following text segment.
87
+ */
88
+ declare function parseMentionSegments(content: string): MentionSegment[];
89
+ /**
90
+ * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible
91
+ * mention HTML spans (<span class="pixerate-mention-node" data-type="mention" ...>),
92
+ * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.
93
+ */
94
+ declare function preprocessMarkdownMentions(content: string, optionsOrMentionables?: MentionEntity[] | PreprocessMarkdownMentionsOptions): string;
95
+
96
+ /**
97
+ * Preprocesses file-protocol and editor-protocol links in markdown content:
98
+ * converts [label](file://...), vscode://, and cursor:// links into anchor tags
99
+ * annotated with data-file-link="true", preserving code backticks in labels.
100
+ */
101
+ declare function preprocessMarkdownFileLinks(content: string): string;
102
+ interface MarkdownToHtmlOptions {
103
+ /**
104
+ * Preprocess file, vscode, and cursor links into clickable data-file-link tags.
105
+ */
106
+ preprocessFileLinks?: boolean;
107
+ /**
108
+ * Whether to preprocess @mentions into TipTap mention node HTML spans.
109
+ */
110
+ preprocessMentions?: boolean;
111
+ /**
112
+ * Pool of mentionables to pass to preprocessMarkdownMentions.
113
+ */
114
+ mentionables?: MentionEntity[];
115
+ /**
116
+ * Full options for preprocessMarkdownMentions.
117
+ */
118
+ preprocessOptions?: PreprocessMarkdownMentionsOptions;
119
+ }
33
120
  /**
34
121
  * Converts a markdown string into HTML suitable for TipTap initial content or setContent.
35
122
  */
36
- declare function markdownToTipTapHtml(markdown: string): string;
123
+ declare function markdownToTipTapHtml(markdown: string, options?: MarkdownToHtmlOptions): string;
37
124
  /**
38
125
  * Extracts clean markdown from a TipTap editor instance.
39
126
  * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().
@@ -41,4 +128,4 @@ declare function markdownToTipTapHtml(markdown: string): string;
41
128
  */
42
129
  declare function getEditorMarkdown(editor: any): string;
43
130
 
44
- export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, plainTextToTipTapHtml };
131
+ export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };
@@ -1,3 +1,8 @@
1
+ import { a as MentionEntity } from '../mention-Dcevh3ff.js';
2
+ import '@tiptap/core';
3
+ import '@tiptap/extension-mention';
4
+ import '@tiptap/suggestion';
5
+
1
6
  /**
2
7
  * Escapes characters that have syntactic meaning in HTML text.
3
8
  */
@@ -30,10 +35,92 @@ interface ExtractedMention {
30
35
  */
31
36
  declare function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[];
32
37
 
38
+ /**
39
+ * Canonical regex pattern for matching @mentions in plain text or markdown.
40
+ * Supports:
41
+ * - Standard unquoted handles: @username, @user.name, @team_alpha, @sa-1
42
+ * - Quoted handles: @"John Doe", &quot;Jane Doe&quot;
43
+ * Unquoted handles exclude trailing punctuation (e.g. @violet. matches "violet" without the dot).
44
+ */
45
+ declare const MENTION_REGEX: RegExp;
46
+ /**
47
+ * Split regex identifying markdown code blocks, inline code, URLs, and existing HTML tags.
48
+ * Used by preprocessMarkdownMentions to ensure non-mention regions remain completely untouched.
49
+ */
50
+ declare const MARKDOWN_MENTION_SPLIT_REGEX: RegExp;
51
+ interface MentionSegment {
52
+ type: "text" | "mention";
53
+ value: string;
54
+ handle?: string;
55
+ }
56
+ interface PreprocessMarkdownMentionsOptions {
57
+ /**
58
+ * Known pool of mentionable entities (users, agents, teams, etc.).
59
+ */
60
+ mentionables?: MentionEntity[];
61
+ /**
62
+ * Default entity type assigned when a handle does not match any entry in mentionables.
63
+ * Defaults to 'user'.
64
+ */
65
+ defaultType?: string;
66
+ /**
67
+ * Custom resolver callback to derive entity metadata for unmatched handles.
68
+ */
69
+ resolveMention?: (handle: string) => Partial<MentionEntity> | null | undefined;
70
+ }
71
+ /**
72
+ * Strips code blocks and inline code from markdown or HTML content:
73
+ * - Fenced code blocks: ```...``` and ~~~...~~~
74
+ * - Inline backtick code: `...`
75
+ * - HTML code/pre tags: <pre>...</pre>, <code>...</code>
76
+ * Used to avoid false-positive mention parsing and keyword analysis within code snippets, terminal logs, or stack traces.
77
+ */
78
+ declare function stripMarkdownCode(content: string): string;
79
+ /**
80
+ * Extracts unique mention handles from a text, markdown, or HTML string,
81
+ * ignoring trailing punctuation, code blocks, URLs, and pre-existing HTML mention attributes.
82
+ */
83
+ declare function extractMentions(content: string): string[];
84
+ /**
85
+ * Segments a text string into plain text parts and mention tokens.
86
+ * Correctly leaves trailing punctuation (like ".") as part of the following text segment.
87
+ */
88
+ declare function parseMentionSegments(content: string): MentionSegment[];
89
+ /**
90
+ * Preprocesses markdown text by turning raw @mention handles into TipTap-compatible
91
+ * mention HTML spans (<span class="pixerate-mention-node" data-type="mention" ...>),
92
+ * ensuring code blocks, inline code, existing mention nodes, and URLs remain immune.
93
+ */
94
+ declare function preprocessMarkdownMentions(content: string, optionsOrMentionables?: MentionEntity[] | PreprocessMarkdownMentionsOptions): string;
95
+
96
+ /**
97
+ * Preprocesses file-protocol and editor-protocol links in markdown content:
98
+ * converts [label](file://...), vscode://, and cursor:// links into anchor tags
99
+ * annotated with data-file-link="true", preserving code backticks in labels.
100
+ */
101
+ declare function preprocessMarkdownFileLinks(content: string): string;
102
+ interface MarkdownToHtmlOptions {
103
+ /**
104
+ * Preprocess file, vscode, and cursor links into clickable data-file-link tags.
105
+ */
106
+ preprocessFileLinks?: boolean;
107
+ /**
108
+ * Whether to preprocess @mentions into TipTap mention node HTML spans.
109
+ */
110
+ preprocessMentions?: boolean;
111
+ /**
112
+ * Pool of mentionables to pass to preprocessMarkdownMentions.
113
+ */
114
+ mentionables?: MentionEntity[];
115
+ /**
116
+ * Full options for preprocessMarkdownMentions.
117
+ */
118
+ preprocessOptions?: PreprocessMarkdownMentionsOptions;
119
+ }
33
120
  /**
34
121
  * Converts a markdown string into HTML suitable for TipTap initial content or setContent.
35
122
  */
36
- declare function markdownToTipTapHtml(markdown: string): string;
123
+ declare function markdownToTipTapHtml(markdown: string, options?: MarkdownToHtmlOptions): string;
37
124
  /**
38
125
  * Extracts clean markdown from a TipTap editor instance.
39
126
  * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().
@@ -41,4 +128,4 @@ declare function markdownToTipTapHtml(markdown: string): string;
41
128
  */
42
129
  declare function getEditorMarkdown(editor: any): string;
43
130
 
44
- export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, plainTextToTipTapHtml };
131
+ export { type ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, type MarkdownToHtmlOptions, type MentionSegment, type PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode };