tiptap-office 0.0.1

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 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config/TiptapOfficeProvider.tsx","../src/components/TiptapEditor.tsx","../src/extensions/indent.ts","../src/components/EditorToolbar.tsx","../src/components/TrackChangesToolbar.tsx","../src/components/CommentsToolbar.tsx","../src/components/ReviewPanel.tsx","../src/components/SuggestionItem.tsx","../src/components/CommentItem.tsx","../src/components/SelectionCommentBubble.tsx","../src/components/InlineCommentPopover.tsx","../src/components/AIChatPanelAgent.tsx","../src/i18n.ts","../src/extensions/suggestionMode.ts","../src/extensions/inlineComment.ts","../src/extensions/nodeId.ts","../src/utils/nodeIdUtils.ts","../src/extensions/sectionId.ts","../src/hooks/useTrackChanges.ts","../src/hooks/useComments.ts","../src/hooks/useEditorAgent.ts","../src/agent/runAgent.ts","../src/agent/providers.ts","../src/agent/systemPrompt.ts","../src/agent/tools.ts","../src/agent/htmlParser.ts","../src/utils/editApplicator.ts","../src/utils/sectionDetector.ts","../src/utils/contentSerializer.ts","../src/agent/htmlSerializer.ts","../src/utils/annotationSerializer.ts","../src/agent/changeTracking.ts","../src/agent/inverseOps.ts","../src/agent/journal.ts","../src/services/editorApi.ts","../src/components/EditOperationCard.tsx","../src/utils/docxToHtml.ts","../src/utils/aiSuggestions.ts"],"sourcesContent":["// --- Config ---\nexport {\n TiptapOfficeProvider,\n useTiptapOfficeConfig,\n type TiptapOfficeConfig,\n type ProviderName,\n} from './config/TiptapOfficeProvider';\n\n// --- Editor + toolbar ---\nexport { default as TiptapEditor } from './components/TiptapEditor';\nexport { default as EditorToolbar } from './components/EditorToolbar';\nexport { default as EditOperationCard } from './components/EditOperationCard';\n\n// --- AI agent ---\nexport { useEditorAgent } from './hooks/useEditorAgent';\nexport type {\n UseEditorAgentReturn,\n AgentChatMessage,\n AgentToolProgress,\n AgentUIState,\n} from './hooks/useEditorAgent';\nexport type {\n AgentPlaybook,\n AgentComplianceAct,\n AgentChange,\n} from './agent/types';\n\n// --- Comments + suggestions hooks ---\nexport { useComments } from './hooks/useComments';\nexport { useTrackChanges } from './hooks/useTrackChanges';\n\n// --- DOCX I/O + helpers ---\nexport { docxToHtml } from './utils/docxToHtml';\nexport { applyAISuggestion, applyAISuggestions } from './utils/aiSuggestions';\nexport { applyEditPlan, operationKey } from './utils/editApplicator';\n\n// --- Public types ---\nexport type {\n Suggestion,\n SuggestionAuthor,\n TrackChangesState,\n Comment,\n CommentReply,\n CommentAuthor,\n CommentSeverity,\n CommentsState,\n} from './types';\nexport type { EditOperation, EditPlan, EditOperationWithStatus } from './types';\n","'use client';\n\nimport { createContext, useContext, type ReactNode } from 'react';\n\nexport type ProviderName = 'anthropic' | 'openai' | 'google';\n\nexport interface TiptapOfficeConfig {\n /** Base URL of your backend (no trailing slash). All editor API calls and\n * the LLM proxy are rooted here. */\n apiBaseUrl: string;\n\n /** Path under `apiBaseUrl` that proxies LLM provider requests. The library\n * POSTs to `${apiBaseUrl}${llmProxyPath}` using the Vercel AI SDK's\n * `baseURL` convention. Defaults to `/llm/proxy`. */\n llmProxyPath?: string;\n\n /** Credentials mode for backend fetches. Defaults to `'include'`\n * (cookie-based auth). Set to `'omit'` for token-only auth. */\n includeCredentials?: RequestCredentials;\n\n /** Returns the headers (e.g. auth) to attach to every backend fetch.\n * May return synchronously or as a promise. */\n getAuthHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n\n /** Returns extra headers for LLM proxy requests, scoped by provider and\n * chat id. Use this if your proxy needs routing hints\n * (e.g. provider selection, per-chat tracing). */\n getProxyHeaders?: (params: { provider: ProviderName; chatId: string }) => Record<string, string>;\n\n /** Default model id (e.g. `'gpt-4o'`, `'claude-3-7-sonnet-latest'`). The\n * consumer must supply this — no vendor model is hardcoded in the library. */\n defaultModel: string;\n\n /** Default provider matching `defaultModel`. */\n defaultProvider: ProviderName;\n}\n\nconst TiptapOfficeContext = createContext<TiptapOfficeConfig | null>(null);\n\nexport function TiptapOfficeProvider({\n config,\n children,\n}: {\n config: TiptapOfficeConfig;\n children: ReactNode;\n}) {\n return (\n <TiptapOfficeContext.Provider value={config}>{children}</TiptapOfficeContext.Provider>\n );\n}\n\nexport function useTiptapOfficeConfig(): TiptapOfficeConfig {\n const ctx = useContext(TiptapOfficeContext);\n if (!ctx) {\n throw new Error(\n 'tiptap-office: components must be wrapped in <TiptapOfficeProvider config={...}>. ' +\n 'See README for the required config shape.',\n );\n }\n return ctx;\n}\n\n/** Resolved fetch options the library uses for every backend call. */\nexport async function buildFetchInit(\n config: TiptapOfficeConfig,\n extra?: RequestInit,\n): Promise<RequestInit> {\n const authHeaders = config.getAuthHeaders ? await config.getAuthHeaders() : {};\n return {\n ...extra,\n credentials: config.includeCredentials ?? 'include',\n headers: {\n 'Content-Type': 'application/json',\n ...authHeaders,\n ...(extra?.headers ?? {}),\n },\n };\n}\n","'use client';\n\nimport React, { useEffect, useCallback, useRef, useState } from 'react';\nimport { useEditor, EditorContent, type Editor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport { Underline } from '@tiptap/extension-underline';\nimport { TextAlign } from '@tiptap/extension-text-align';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport { Color } from '@tiptap/extension-color';\nimport { FontFamily } from '@tiptap/extension-font-family';\nimport { Highlight } from '@tiptap/extension-highlight';\nimport { Image } from '@tiptap/extension-image';\nimport { Table } from '@tiptap/extension-table';\nimport { TableRow } from '@tiptap/extension-table-row';\nimport { TableCell } from '@tiptap/extension-table-cell';\nimport { TableHeader } from '@tiptap/extension-table-header';\nimport { Placeholder } from '@tiptap/extension-placeholder';\nimport { Indent } from '../extensions/indent';\nimport EditorToolbar from './EditorToolbar';\nimport ReviewPanel from './ReviewPanel';\nimport SelectionCommentBubble from './SelectionCommentBubble';\nimport InlineCommentPopover from './InlineCommentPopover';\nimport type { ReviewTab } from './ReviewPanel';\nimport AIChatPanelAgent from './AIChatPanelAgent';\nimport { SuggestionMode, SuggestionInsertMark, SuggestionDeleteMark, SuggestionModificationMark, LegacySuggestionInsertMark, LegacySuggestionDeleteMark } from '../extensions/suggestionMode';\nimport { isSuggestChangesEnabled } from '@blocknote/prosemirror-suggest-changes';\nimport { InlineCommentMark, InlineComments } from '../extensions/inlineComment';\nimport { NodeId } from '../extensions/nodeId';\nimport { SectionId } from '../extensions/sectionId';\nimport { useTrackChanges } from '../hooks/useTrackChanges';\nimport { useComments } from '../hooks/useComments';\nimport { useEditorAgent } from '../hooks/useEditorAgent';\nimport type { Comment } from '../types';\nimport '../styles/tracked-changes.css';\nimport '../styles/comments.css';\nimport '../styles/ai-drafting.css';\n\ninterface TiptapEditorProps {\n content: string | Record<string, unknown>;\n onChange?: (html: string) => void;\n onJsonChange?: (json: Record<string, unknown>) => void;\n onCommentsChange?: (comments: Comment[]) => void;\n onEditorReady?: (editor: Editor) => void;\n editable?: boolean;\n /** Reviewer mode: editable but locked to suggestion mode + comments only */\n reviewerMode?: boolean;\n placeholder?: string;\n username?: string;\n draftId?: string;\n documentId?: string;\n /** Enable persistent node-id extension (needed for AI edit operations) */\n enableNodeIds?: boolean;\n /** Enable AI drafting panel + section indexing hooks */\n enableAIDrafting?: boolean;\n /** Override the prose content area class (e.g. to center/constrain width) */\n contentClassName?: string;\n /** Force show comment bubble even when not editable (e.g. locked canvas) */\n forceShowCommentBubble?: boolean;\n /** When viewing a historical version, comment actions are read-only */\n isHistoricalVersion?: boolean;\n /** Show toolbar even when editor is not editable (e.g. locked canvas still needs AI/comment tools) */\n showToolbar?: boolean;\n}\n\nconst TiptapEditor: React.FC<TiptapEditorProps> = ({\n content,\n onChange,\n onJsonChange,\n onCommentsChange,\n onEditorReady,\n editable = true,\n reviewerMode = false,\n placeholder = 'Start typing your document...',\n username = 'Anonymous',\n draftId = 'default',\n documentId = 'default',\n enableNodeIds = true,\n enableAIDrafting = true,\n contentClassName,\n forceShowCommentBubble = false,\n isHistoricalVersion = false,\n showToolbar,\n}) => {\n // Refs for debounced onUpdate to avoid stale closures\n const onChangeRef = useRef(onChange);\n const onJsonChangeRef = useRef(onJsonChange);\n const onCommentsChangeRef = useRef(onCommentsChange);\n const updateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n onChangeRef.current = onChange;\n onJsonChangeRef.current = onJsonChange;\n onCommentsChangeRef.current = onCommentsChange;\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: {\n levels: [1, 2, 3, 4, 5, 6],\n },\n underline: false,\n }),\n Underline,\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n TextAlign.configure({\n types: ['heading', 'paragraph'],\n }),\n Image.configure({\n inline: false,\n allowBase64: true,\n }),\n Table.configure({\n resizable: true,\n }),\n TableRow,\n TableCell,\n TableHeader,\n Indent.configure({\n types: ['paragraph', 'heading'],\n }),\n Placeholder.configure({\n placeholder,\n }),\n // Track changes marks and plugin (new library)\n SuggestionInsertMark,\n SuggestionDeleteMark,\n SuggestionModificationMark,\n // Legacy marks for backward compatibility with existing saved documents\n LegacySuggestionInsertMark,\n LegacySuggestionDeleteMark,\n SuggestionMode.configure({\n enabled: false,\n username,\n }),\n // Inline comments\n InlineCommentMark,\n InlineComments,\n // Preserves business-identifier sectionId attrs as data-section on the DOM.\n SectionId,\n ...(enableNodeIds\n ? [\n NodeId.configure({\n types: ['paragraph', 'heading', 'listItem', 'table', 'tableCell', 'tableHeader'],\n }),\n ]\n : []),\n ],\n content,\n editable,\n immediatelyRender: false,\n onUpdate: ({ editor }) => {\n // Debounce expensive serialization to avoid OOM on rapid typing\n if (updateTimerRef.current) clearTimeout(updateTimerRef.current);\n updateTimerRef.current = setTimeout(() => {\n if (onChangeRef.current) {\n onChangeRef.current(editor.getHTML());\n }\n if (onJsonChangeRef.current) {\n onJsonChangeRef.current(editor.getJSON());\n }\n }, 300);\n },\n editorProps: {\n attributes: {\n class: contentClassName ?? 'prose prose-stone dark:prose-invert max-w-none focus:outline-none min-h-[500px] p-8',\n },\n },\n });\n\n // Cleanup debounce timer on unmount\n useEffect(() => {\n return () => {\n if (updateTimerRef.current) clearTimeout(updateTimerRef.current);\n };\n }, []);\n\n const initialComments = React.useMemo(() => {\n if (content && typeof content === 'object' && 'comments' in content && Array.isArray(content.comments)) {\n return content.comments as Comment[];\n }\n return [];\n }, [content]);\n\n const trackChanges = useTrackChanges(editor);\n const commentsState = useComments(editor, draftId, username, initialComments);\n const agent = useEditorAgent(\n enableAIDrafting ? editor : null,\n documentId,\n {\n onAICommentsCreated: commentsState.addBatchComments,\n comments: commentsState.comments,\n suggestions: trackChanges.suggestions,\n onCommentsResolved: commentsState.resolveCommentsByIds,\n },\n );\n\n // Merged review panel state\n const [showReviewPanel, setShowReviewPanel] = useState(false);\n const [reviewTab, setReviewTab] = useState<ReviewTab>('suggestions');\n\n // Inline comment popover state (Confluence-style)\n const [popoverComment, setPopoverComment] = useState<{ comment: import('../types').Comment; position: { top: number; left: number } } | null>(null);\n\n // When any comment highlight or dot is clicked, show the inline popover\n // (both AI and human comments use the same inline popover)\n useEffect(() => {\n const info = commentsState.clickedCommentInfo;\n if (!info || !editor) return;\n\n const comment = commentsState.comments.find((c) => c.id === info.commentId);\n if (!comment) return;\n\n try {\n const coords = editor.view.coordsAtPos(comment.from);\n setPopoverComment({\n comment,\n position: { top: coords.bottom, left: coords.left },\n });\n } catch {\n // Ignore if coords fail — popover just won't show\n }\n\n commentsState.setClickedCommentInfo(null);\n }, [commentsState.clickedCommentInfo, editor]);\n\n // When comments hook signals panel open (e.g. from SelectionCommentBubble),\n // open the review panel on the comments tab.\n useEffect(() => {\n if (commentsState.showPanel) {\n setShowReviewPanel(true);\n setReviewTab('comments');\n commentsState.setShowPanel(false);\n }\n }, [commentsState.showPanel]);\n\n // Keep inline popover comment in sync with comment state (e.g. after reply/resolve)\n useEffect(() => {\n if (!popoverComment) return;\n const updated = commentsState.comments.find((c) => c.id === popoverComment.comment.id);\n if (!updated) {\n setPopoverComment(null);\n } else if (updated !== popoverComment.comment) {\n setPopoverComment((prev) => prev ? { ...prev, comment: updated } : null);\n }\n }, [commentsState.comments, popoverComment?.comment.id]);\n\n useEffect(() => {\n if (onCommentsChangeRef.current) {\n onCommentsChangeRef.current(commentsState.comments);\n }\n }, [commentsState.comments]);\n\n // In reviewer mode, force suggestion mode on and prevent toggling off\n useEffect(() => {\n if (reviewerMode && editor && !trackChanges.enabled) {\n editor.commands.enableSuggestionMode();\n }\n }, [reviewerMode, editor, trackChanges.enabled]);\n\n // Notify parent when editor is ready\n useEffect(() => {\n if (editor && onEditorReady) {\n onEditorReady(editor);\n }\n }, [editor, onEditorReady]);\n\n // Sync content prop into the editor on mount only.\n // After the initial set, the editor is the source of truth — external prop\n // changes (e.g. from a query refetch) must NOT overwrite user edits.\n const initialContentSet = useRef(false);\n useEffect(() => {\n if (!editor) return;\n if (!content) return; // Skip empty content — editor already has a default empty doc\n\n if (!initialContentSet.current) {\n // Check actual plugin state (React state may lag behind).\n // Temporarily disable suggestion mode while loading content so the\n // plugin doesn't intercept setContent and mark everything as a suggestion.\n const wasSuggestionMode = isSuggestChangesEnabled(editor.state);\n if (wasSuggestionMode) {\n editor.commands.disableSuggestionMode();\n }\n\n editor.commands.setContent(content);\n initialContentSet.current = true;\n\n if (wasSuggestionMode) {\n editor.commands.enableSuggestionMode();\n }\n }\n }, [content, editor]);\n\n // Update editable state\n useEffect(() => {\n if (editor) {\n editor.setEditable(editable);\n }\n }, [editable, editor]);\n\n // Scroll to a position range in the editor\n const scrollToRange = useCallback(\n (range: { from: number; to: number }) => {\n if (!editor) return;\n editor.chain().setTextSelection({ from: range.from, to: range.to }).focus().run();\n\n const { view } = editor;\n const coords = view.coordsAtPos(range.from);\n const editorDom = view.dom.closest('.overflow-auto');\n if (editorDom && coords) {\n const containerRect = editorDom.getBoundingClientRect();\n const scrollTop = editorDom.scrollTop + coords.top - containerRect.top - containerRect.height / 3;\n editorDom.scrollTo({ top: scrollTop, behavior: 'smooth' });\n }\n },\n [editor]\n );\n\n const handleScrollToSuggestion = useCallback(\n (suggestion: { from: number; to: number }) => scrollToRange(suggestion),\n [scrollToRange]\n );\n\n const handleScrollToComment = useCallback(\n (comment: { from: number; to: number; id?: string }) => {\n scrollToRange(comment);\n if (comment.id) {\n commentsState.setActiveCommentId(comment.id);\n }\n },\n [scrollToRange, commentsState]\n );\n\n return (\n <div className=\"flex flex-col h-full bg-white dark:bg-stone-900 rounded-lg overflow-hidden border border-stone-200 dark:border-stone-700\">\n {(showToolbar ?? editable) && (\n <EditorToolbar\n editor={editor}\n trackChanges={trackChanges}\n comments={commentsState}\n aiDrafting={reviewerMode || !enableAIDrafting ? undefined : agent}\n reviewerMode={reviewerMode}\n reviewPanelOpen={showReviewPanel}\n onToggleReviewPanel={() => setShowReviewPanel((prev) => !prev)}\n />\n )}\n <div className=\"flex flex-1 min-h-0\">\n <div className=\"flex-1 overflow-auto\">\n <EditorContent editor={editor} />\n {/* Floating comment bubble — appears on text selection (never on historical versions) */}\n {!isHistoricalVersion && (forceShowCommentBubble || editable) && editor && (\n <SelectionCommentBubble editor={editor} comments={commentsState} />\n )}\n {/* Inline comment popover — Confluence-style, appears near highlighted text on click */}\n {popoverComment && (\n <InlineCommentPopover\n comment={popoverComment.comment}\n position={popoverComment.position}\n comments={commentsState}\n onClose={() => setPopoverComment(null)}\n readOnly={reviewerMode}\n isHistoricalVersion={isHistoricalVersion}\n />\n )}\n </div>\n {showReviewPanel && (\n <ReviewPanel\n activeTab={reviewTab}\n onTabChange={setReviewTab}\n onClose={() => setShowReviewPanel(false)}\n trackChanges={trackChanges}\n commentsState={commentsState}\n editor={editor}\n onScrollToSuggestion={handleScrollToSuggestion}\n onScrollToComment={handleScrollToComment}\n readOnly={reviewerMode}\n isHistoricalVersion={isHistoricalVersion}\n />\n )}\n {enableAIDrafting && agent.isPanelOpen && (\n <div className=\"w-[380px] flex-shrink-0 ai-panel-enter\">\n <AIChatPanelAgent agent={agent} editor={editor} />\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default TiptapEditor;\n","import { Extension } from '@tiptap/core';\n\nexport interface IndentOptions {\n types: string[];\n maxLevel: number;\n pxPerLevel: number;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n indent: {\n indent: () => ReturnType;\n outdent: () => ReturnType;\n };\n }\n}\n\nexport const Indent = Extension.create<IndentOptions>({\n name: 'indent',\n\n addOptions() {\n return {\n types: ['paragraph', 'heading'],\n maxLevel: 10,\n pxPerLevel: 48,\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n indent: {\n default: 0,\n parseHTML: (element) => {\n const dataIndent = element.getAttribute('data-indent');\n if (dataIndent) {\n const val = parseInt(dataIndent, 10);\n if (!isNaN(val) && val > 0) return val;\n }\n\n const style = element.getAttribute('style') || '';\n const match = style.match(/margin-left:\\s*(\\d+(?:\\.\\d+)?)px/);\n if (match) {\n return Math.max(1, Math.round(parseFloat(match[1]) / 48));\n }\n\n return 0;\n },\n renderHTML: (attributes) => {\n if (!attributes.indent || attributes.indent <= 0) return {};\n return {\n 'data-indent': attributes.indent,\n style: `margin-left: ${attributes.indent * 48}px`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n indent:\n () =>\n ({ tr, state, dispatch }) => {\n const { from, to } = state.selection;\n let changed = false;\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (this.options.types.includes(node.type.name)) {\n const current = (node.attrs.indent as number) || 0;\n if (current < this.options.maxLevel) {\n if (dispatch) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n indent: current + 1,\n });\n }\n changed = true;\n }\n }\n });\n\n return changed;\n },\n\n outdent:\n () =>\n ({ tr, state, dispatch }) => {\n const { from, to } = state.selection;\n let changed = false;\n\n state.doc.nodesBetween(from, to, (node, pos) => {\n if (this.options.types.includes(node.type.name)) {\n const current = (node.attrs.indent as number) || 0;\n if (current > 0) {\n if (dispatch) {\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n indent: current - 1,\n });\n }\n changed = true;\n }\n }\n });\n\n return changed;\n },\n };\n },\n\n addKeyboardShortcuts() {\n return {\n Tab: () => this.editor.commands.indent(),\n 'Shift-Tab': () => this.editor.commands.outdent(),\n };\n },\n});\n","'use client';\n\nimport React, { useState, useEffect, useRef } from 'react';\nimport { Editor } from '@tiptap/react';\nimport {\n Bold,\n Italic,\n Underline,\n Strikethrough,\n List,\n ListOrdered,\n AlignLeft,\n AlignCenter,\n AlignRight,\n AlignJustify,\n Heading1,\n Heading2,\n Heading3,\n Quote,\n Minus,\n Undo,\n Redo,\n Table,\n RemoveFormatting,\n Plus,\n Trash2,\n RowsIcon,\n Columns,\n Palette,\n IndentIncrease,\n IndentDecrease,\n Highlighter,\n ChevronDown,\n Sparkles,\n PanelRight,\n} from 'lucide-react';\nimport TrackChangesToolbar from './TrackChangesToolbar';\nimport CommentsToolbar from './CommentsToolbar';\nimport type { UseTrackChangesReturn } from '../hooks/useTrackChanges';\nimport type { UseCommentsReturn } from '../hooks/useComments';\n\n/** Subset of the agent hook the toolbar actually uses — keeps the toolbar\n * decoupled from the full UseEditorAgentReturn surface. */\ninterface PanelController {\n isPanelOpen: boolean;\n openPanel: () => void;\n closePanel: () => void;\n}\n\ninterface EditorToolbarProps {\n editor: Editor | null;\n trackChanges?: UseTrackChangesReturn;\n comments?: UseCommentsReturn;\n aiDrafting?: PanelController;\n /** Reviewer mode: only show track changes + comments toolbar */\n reviewerMode?: boolean;\n /** Whether the review panel is currently open */\n reviewPanelOpen?: boolean;\n /** Toggle the review panel */\n onToggleReviewPanel?: () => void;\n}\n\ninterface ToolbarButtonProps {\n onClick: () => void;\n isActive?: boolean;\n disabled?: boolean;\n children: React.ReactNode;\n title?: string;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n onClick,\n isActive = false,\n disabled = false,\n children,\n title,\n}) => (\n <button\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={`\n w-7 h-7 flex items-center justify-center rounded flex-shrink-0 transition-colors\n ${isActive\n ? 'bg-[#111111] text-white dark:bg-white dark:text-[#111111]'\n : 'text-stone-500 dark:text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-700'\n }\n ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}\n `}\n >\n {children}\n </button>\n);\n\nconst AIToolbarButton: React.FC<Omit<ToolbarButtonProps, 'isActive'> & { isActive?: boolean }> = ({\n onClick,\n isActive = false,\n disabled = false,\n children,\n title,\n}) => (\n <button\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={`\n w-7 h-7 flex items-center justify-center rounded flex-shrink-0 transition-colors\n ${isActive\n ? 'bg-violet-200 text-violet-700 dark:bg-violet-800/50 dark:text-violet-300'\n : 'bg-violet-50 text-violet-500 dark:bg-violet-900/20 dark:text-violet-400 hover:bg-violet-100 hover:text-violet-600 dark:hover:bg-violet-900/30 dark:hover:text-violet-300'\n }\n ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}\n `}\n >\n {children}\n </button>\n);\n\nconst ToolbarDivider: React.FC = () => (\n <div className=\"w-px h-4 bg-stone-200 dark:bg-stone-600 mx-1 flex-shrink-0\" />\n);\n\nconst TEXT_COLORS = [\n { label: 'Default', value: '' },\n { label: 'Black', value: '#000000' },\n { label: 'Dark Gray', value: '#444444' },\n { label: 'Gray', value: '#888888' },\n { label: 'Red', value: '#ef4444' },\n { label: 'Orange', value: '#f97316' },\n { label: 'Yellow', value: '#eab308' },\n { label: 'Green', value: '#22c55e' },\n { label: 'Blue', value: '#3b82f6' },\n { label: 'Purple', value: '#a855f7' },\n { label: 'Pink', value: '#ec4899' },\n { label: 'Teal', value: '#14b8a6' },\n];\n\nconst HIGHLIGHT_COLORS = [\n { label: 'None', value: '' },\n { label: 'Yellow', value: '#fef08a' },\n { label: 'Green', value: '#bbf7d0' },\n { label: 'Blue', value: '#bfdbfe' },\n { label: 'Pink', value: '#fbcfe8' },\n { label: 'Orange', value: '#fed7aa' },\n { label: 'Purple', value: '#e9d5ff' },\n { label: 'Red', value: '#fecaca' },\n { label: 'Teal', value: '#ccfbf1' },\n];\n\nconst FONT_FAMILIES = [\n { label: 'Default', value: '' },\n { label: 'Serif', value: 'Georgia, serif' },\n { label: 'Sans Serif', value: 'Arial, sans-serif' },\n { label: 'Monospace', value: 'Courier New, monospace' },\n { label: 'Cursive', value: 'cursive' },\n { label: 'Times New Roman', value: 'Times New Roman, serif' },\n { label: 'Verdana', value: 'Verdana, sans-serif' },\n { label: 'Trebuchet MS', value: 'Trebuchet MS, sans-serif' },\n];\n\nconst ColorPickerDropdown: React.FC<{\n colors: { label: string; value: string }[];\n activeColor: string;\n onSelect: (color: string) => void;\n onClose: () => void;\n}> = ({ colors, activeColor, onSelect, onClose }) => {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [onClose]);\n\n return (\n <div\n ref={ref}\n className=\"absolute top-full left-0 mt-1 p-2 bg-white dark:bg-stone-800 border border-stone-200 dark:border-stone-600 rounded-lg shadow-lg z-50 grid grid-cols-4 gap-1 min-w-[160px]\"\n >\n {colors.map((color) => (\n <button\n key={color.label}\n title={color.label}\n onClick={() => {\n onSelect(color.value);\n onClose();\n }}\n className={`w-7 h-7 rounded border transition-transform hover:scale-110 ${\n activeColor === color.value\n ? 'ring-2 ring-[#111111] dark:ring-white ring-offset-1'\n : 'border-stone-300 dark:border-stone-600'\n }`}\n style={{\n backgroundColor: color.value || 'transparent',\n backgroundImage: !color.value\n ? 'linear-gradient(135deg, transparent 45%, #ef4444 45%, #ef4444 55%, transparent 55%)'\n : undefined,\n }}\n />\n ))}\n </div>\n );\n};\n\nconst EditorToolbar: React.FC<EditorToolbarProps> = ({ editor, trackChanges, comments, aiDrafting, reviewerMode = false, reviewPanelOpen = false, onToggleReviewPanel }) => {\n // Force re-render on selection/transaction changes so toolbar updates\n const [, setForceUpdate] = useState(0);\n const toolbarUpdateRafRef = useRef<number | null>(null);\n const [showTextColor, setShowTextColor] = useState(false);\n const [showHighlight, setShowHighlight] = useState(false);\n\n useEffect(() => {\n if (!editor || reviewerMode) return; // Skip for reviewer — no formatting buttons to update\n\n const handleUpdate = () => {\n if (toolbarUpdateRafRef.current !== null) return;\n toolbarUpdateRafRef.current = requestAnimationFrame(() => {\n toolbarUpdateRafRef.current = null;\n setForceUpdate((prev) => prev + 1);\n });\n };\n\n editor.on('selectionUpdate', handleUpdate);\n editor.on('transaction', handleUpdate);\n\n return () => {\n editor.off('selectionUpdate', handleUpdate);\n editor.off('transaction', handleUpdate);\n if (toolbarUpdateRafRef.current !== null) {\n cancelAnimationFrame(toolbarUpdateRafRef.current);\n toolbarUpdateRafRef.current = null;\n }\n };\n }, [editor, reviewerMode]);\n\n if (!editor) {\n return null;\n }\n\n\n const addTable = () => {\n if (editor.can().insertTable?.({ rows: 3, cols: 3, withHeaderRow: true })) {\n editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();\n }\n };\n\n return (\n <div className=\"flex flex-nowrap items-center gap-0.5 px-2 py-1.5 border-b border-stone-200 dark:border-stone-700 bg-white dark:bg-[#111111]/10 overflow-x-auto\">\n {/* Reviewer mode: only show track changes + comments */}\n {reviewerMode && (\n <>\n <span className=\"text-xs text-amber-600 dark:text-amber-400 font-medium px-2 py-1 bg-amber-50 dark:bg-amber-900/20 rounded\">\n Review Mode\n </span>\n {trackChanges && (\n <>\n <ToolbarDivider />\n <TrackChangesToolbar trackChanges={trackChanges} locked />\n </>\n )}\n {comments && editor && (\n <>\n <ToolbarDivider />\n <CommentsToolbar comments={comments} editor={editor} />\n </>\n )}\n {(trackChanges || comments) && (\n <>\n <ToolbarDivider />\n <ToolbarButton\n onClick={() => onToggleReviewPanel?.()}\n isActive={reviewPanelOpen}\n title=\"Review Panel\"\n >\n <PanelRight size={18} />\n </ToolbarButton>\n </>\n )}\n </>\n )}\n\n {/* Full toolbar for non-reviewer mode */}\n {!reviewerMode && (\n <>\n {/* Undo/Redo */}\n <ToolbarButton\n onClick={() => editor.chain().focus().undo().run()}\n disabled={!editor.can().undo()}\n title=\"Undo\"\n >\n <Undo size={15} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().redo().run()}\n disabled={!editor.can().redo()}\n title=\"Redo\"\n >\n <Redo size={15} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Headings */}\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}\n isActive={editor.isActive('heading', { level: 1 })}\n title=\"Heading 1\"\n >\n <Heading1 size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}\n isActive={editor.isActive('heading', { level: 2 })}\n title=\"Heading 2\"\n >\n <Heading2 size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}\n isActive={editor.isActive('heading', { level: 3 })}\n title=\"Heading 3\"\n >\n <Heading3 size={18} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Text Formatting */}\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleBold().run()}\n isActive={editor.isActive('bold')}\n title=\"Bold\"\n >\n <Bold size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleItalic().run()}\n isActive={editor.isActive('italic')}\n title=\"Italic\"\n >\n <Italic size={18} />\n </ToolbarButton>\n {editor.can().toggleUnderline?.() && (\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n isActive={editor.isActive('underline')}\n title=\"Underline\"\n >\n <Underline size={18} />\n </ToolbarButton>\n )}\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleStrike().run()}\n isActive={editor.isActive('strike')}\n title=\"Strikethrough\"\n >\n <Strikethrough size={18} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Text Color */}\n <div className=\"relative\">\n <ToolbarButton\n onClick={() => { setShowTextColor(!showTextColor); setShowHighlight(false); }}\n isActive={!!editor.getAttributes('textStyle').color}\n title=\"Text Color\"\n >\n <div className=\"flex flex-col items-center gap-0.5\">\n <Palette size={16} />\n <div\n className=\"w-4 h-1 rounded-sm\"\n style={{ backgroundColor: editor.getAttributes('textStyle').color || '#444444' }}\n />\n </div>\n </ToolbarButton>\n {showTextColor && (\n <ColorPickerDropdown\n colors={TEXT_COLORS}\n activeColor={editor.getAttributes('textStyle').color || ''}\n onSelect={(color) => {\n if (color) {\n editor.chain().focus().setColor(color).run();\n } else {\n editor.chain().focus().unsetColor().run();\n }\n }}\n onClose={() => setShowTextColor(false)}\n />\n )}\n </div>\n\n {/* Highlight Color */}\n <div className=\"relative\">\n <ToolbarButton\n onClick={() => { setShowHighlight(!showHighlight); setShowTextColor(false); }}\n isActive={editor.isActive('highlight')}\n title=\"Highlight\"\n >\n <div className=\"flex flex-col items-center gap-0.5\">\n <Highlighter size={16} />\n <div\n className=\"w-4 h-1 rounded-sm\"\n style={{ backgroundColor: editor.getAttributes('highlight').color || '#fef08a' }}\n />\n </div>\n </ToolbarButton>\n {showHighlight && (\n <ColorPickerDropdown\n colors={HIGHLIGHT_COLORS}\n activeColor={editor.getAttributes('highlight').color || ''}\n onSelect={(color) => {\n if (color) {\n editor.chain().focus().toggleHighlight({ color }).run();\n } else {\n editor.chain().focus().unsetHighlight().run();\n }\n }}\n onClose={() => setShowHighlight(false)}\n />\n )}\n </div>\n\n {/* Font Family */}\n <select\n value={editor.getAttributes('textStyle').fontFamily || ''}\n onChange={(e) => {\n if (e.target.value) {\n editor.chain().focus().setFontFamily(e.target.value).run();\n } else {\n editor.chain().focus().unsetFontFamily().run();\n }\n }}\n title=\"Font Family\"\n className=\"h-8 px-2 text-xs rounded-md border border-stone-300 dark:border-stone-600 bg-white dark:bg-stone-800 text-stone-700 dark:text-stone-300 cursor-pointer hover:bg-stone-100 dark:hover:bg-stone-700 focus:outline-none focus:ring-1 focus:ring-[#111111]\"\n >\n {FONT_FAMILIES.map((font) => (\n <option key={font.label} value={font.value}>\n {font.label}\n </option>\n ))}\n </select>\n\n <ToolbarDivider />\n\n {/* Alignment - only show if text align extension is loaded */}\n {editor.can().setTextAlign?.('left') && (\n <>\n <ToolbarButton\n onClick={() => editor.chain().focus().setTextAlign('left').run()}\n isActive={editor.isActive({ textAlign: 'left' })}\n title=\"Align Left\"\n >\n <AlignLeft size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().setTextAlign('center').run()}\n isActive={editor.isActive({ textAlign: 'center' })}\n title=\"Align Center\"\n >\n <AlignCenter size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().setTextAlign('right').run()}\n isActive={editor.isActive({ textAlign: 'right' })}\n title=\"Align Right\"\n >\n <AlignRight size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().setTextAlign('justify').run()}\n isActive={editor.isActive({ textAlign: 'justify' })}\n title=\"Justify\"\n >\n <AlignJustify size={18} />\n </ToolbarButton>\n <ToolbarDivider />\n </>\n )}\n\n {/* Lists */}\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n isActive={editor.isActive('bulletList')}\n title=\"Bullet List\"\n >\n <List size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n isActive={editor.isActive('orderedList')}\n title=\"Numbered List\"\n >\n <ListOrdered size={18} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Indent */}\n <ToolbarButton\n onClick={() => editor.chain().focus().indent().run()}\n title=\"Increase Indent\"\n >\n <IndentIncrease size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().outdent().run()}\n title=\"Decrease Indent\"\n >\n <IndentDecrease size={18} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Block Elements */}\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n isActive={editor.isActive('blockquote')}\n title=\"Block Quote\"\n >\n <Quote size={18} />\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().setHorizontalRule().run()}\n title=\"Horizontal Rule\"\n >\n <Minus size={18} />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n {/* Table */}\n {editor.can().insertTable?.({ rows: 3, cols: 3, withHeaderRow: true }) && (\n <ToolbarButton onClick={addTable} title=\"Insert Table\">\n <Table size={18} />\n </ToolbarButton>\n )}\n\n {/* Table Controls - only show when inside a table */}\n {editor.isActive('table') && (\n <>\n <ToolbarDivider />\n <ToolbarButton\n onClick={() => editor.chain().focus().addRowBefore().run()}\n title=\"Add Row Above\"\n >\n <div className=\"flex items-center\">\n <RowsIcon size={14} />\n <Plus size={10} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().addRowAfter().run()}\n title=\"Add Row Below\"\n >\n <div className=\"flex items-center\">\n <Plus size={10} />\n <RowsIcon size={14} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().addColumnBefore().run()}\n title=\"Add Column Left\"\n >\n <div className=\"flex items-center\">\n <Columns size={14} />\n <Plus size={10} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().addColumnAfter().run()}\n title=\"Add Column Right\"\n >\n <div className=\"flex items-center\">\n <Plus size={10} />\n <Columns size={14} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().deleteRow().run()}\n title=\"Delete Row\"\n >\n <div className=\"flex items-center text-red-500\">\n <RowsIcon size={14} />\n <Trash2 size={10} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().deleteColumn().run()}\n title=\"Delete Column\"\n >\n <div className=\"flex items-center text-red-500\">\n <Columns size={14} />\n <Trash2 size={10} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n <ToolbarButton\n onClick={() => editor.chain().focus().deleteTable().run()}\n title=\"Delete Table\"\n >\n <div className=\"flex items-center text-red-500\">\n <Table size={14} />\n <Trash2 size={10} className=\"-ml-1\" />\n </div>\n </ToolbarButton>\n </>\n )}\n\n <ToolbarDivider />\n\n {/* Clear Formatting */}\n <ToolbarButton\n onClick={() => editor.chain().focus().clearNodes().unsetAllMarks().run()}\n title=\"Clear Formatting\"\n >\n <RemoveFormatting size={18} />\n </ToolbarButton>\n\n {/* Track Changes */}\n {trackChanges && (\n <>\n <ToolbarDivider />\n <TrackChangesToolbar trackChanges={trackChanges} />\n </>\n )}\n\n {/* Review Panel toggle */}\n {(trackChanges || comments) && (\n <>\n <ToolbarDivider />\n <ToolbarButton\n onClick={() => onToggleReviewPanel?.()}\n isActive={reviewPanelOpen}\n title=\"Review Panel\"\n >\n <PanelRight size={18} />\n </ToolbarButton>\n </>\n )}\n\n {/* AI Editing */}\n {aiDrafting && (\n <>\n <ToolbarDivider />\n <AIToolbarButton\n onClick={() => aiDrafting.isPanelOpen ? aiDrafting.closePanel() : aiDrafting.openPanel()}\n isActive={aiDrafting.isPanelOpen}\n title=\"AI Edit\"\n >\n <Sparkles size={15} />\n </AIToolbarButton>\n </>\n )}\n </>\n )}\n </div>\n );\n};\n\nexport default EditorToolbar;\n","'use client';\n\nimport React from 'react';\nimport { GitCompare } from 'lucide-react';\nimport type { UseTrackChangesReturn } from '../hooks/useTrackChanges';\n\ninterface ToolbarButtonProps {\n onClick: () => void;\n isActive?: boolean;\n disabled?: boolean;\n children: React.ReactNode;\n title?: string;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n onClick,\n isActive = false,\n disabled = false,\n children,\n title,\n}) => (\n <button\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={`\n p-2 rounded-md transition-colors\n ${isActive\n ? 'bg-[#111111] text-white'\n : 'text-stone-600 dark:text-stone-400 hover:bg-stone-200 dark:hover:bg-stone-700'\n }\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}\n `}\n >\n {children}\n </button>\n);\n\ninterface TrackChangesToolbarProps {\n trackChanges: UseTrackChangesReturn;\n /** When locked, suggestion mode cannot be toggled off and accept/reject are hidden */\n locked?: boolean;\n}\n\nconst TrackChangesToolbar: React.FC<TrackChangesToolbarProps> = ({ trackChanges, locked = false }) => {\n const { enabled, suggestionCount, toggleSuggestionMode } = trackChanges;\n\n return (\n <div className=\"flex items-center gap-1\">\n {/* Toggle suggestion mode — disabled when locked (reviewer) */}\n <ToolbarButton\n onClick={locked ? () => {} : toggleSuggestionMode}\n isActive={enabled}\n disabled={locked}\n title={locked ? 'Suggestion mode (locked for reviewers)' : enabled ? 'Disable Track Changes' : 'Enable Track Changes'}\n >\n <GitCompare size={18} />\n </ToolbarButton>\n\n {/* Suggestion count badge */}\n {suggestionCount > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs font-medium rounded-full bg-stone-200 dark:bg-stone-700 text-stone-600 dark:text-stone-300\">\n {suggestionCount}\n </span>\n )}\n </div>\n );\n};\n\nexport default TrackChangesToolbar;\n","'use client';\n\nimport React from 'react';\nimport { MessageSquarePlus, Sparkles, User } from 'lucide-react';\nimport { Editor } from '@tiptap/react';\nimport type { UseCommentsReturn } from '../hooks/useComments';\n\nexport type CommentFilter = 'all' | 'human' | 'ai';\n\ninterface CommentsToolbarProps {\n comments: UseCommentsReturn;\n editor: Editor;\n filter?: CommentFilter;\n onFilterChange?: (filter: CommentFilter) => void;\n}\n\nconst CommentsToolbar: React.FC<CommentsToolbarProps> = ({\n comments,\n editor,\n filter = 'all',\n onFilterChange,\n}) => {\n const { from, to } = editor.state.selection;\n const hasSelection = from !== to;\n\n const humanCount = comments.comments.filter((c) => !c.author.isAI).length;\n const aiCount = comments.comments.filter((c) => c.author.isAI).length;\n const hasMultipleSources = humanCount > 0 && aiCount > 0;\n\n return (\n <div className=\"flex items-center gap-1\">\n {/* Add Comment */}\n <button\n onMouseDown={(e) => {\n // Prevent this button from stealing focus/selection from the editor\n e.preventDefault();\n if (hasSelection) {\n comments.captureSelection();\n comments.setShowPanel(true);\n }\n }}\n disabled={!hasSelection}\n title={hasSelection ? 'Add Comment' : 'Select text to comment'}\n className={`\n p-2 rounded-md transition-colors\n ${!hasSelection ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}\n text-stone-600 dark:text-stone-400 hover:bg-stone-200 dark:hover:bg-stone-700\n `}\n >\n <MessageSquarePlus size={18} className=\"text-amber-600 dark:text-amber-400\" />\n </button>\n\n {/* Comment count badge */}\n {comments.commentCount > 0 && (\n <span className=\"ml-1 px-2 py-0.5 text-xs font-medium rounded-full bg-stone-200 dark:bg-stone-700 text-stone-600 dark:text-stone-300\">\n {comments.commentCount}\n </span>\n )}\n\n {/* Filter toggle — only show when both AI and human comments exist */}\n {hasMultipleSources && onFilterChange && (\n <div className=\"ml-2 flex items-center rounded-md border border-stone-200 dark:border-stone-700 overflow-hidden\">\n <button\n onClick={() => onFilterChange('all')}\n className={`px-2 py-1 text-[10px] font-medium transition-colors ${\n filter === 'all'\n ? 'bg-stone-800 text-white dark:bg-white dark:text-stone-800'\n : 'text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-800'\n }`}\n >\n All\n </button>\n <button\n onClick={() => onFilterChange('human')}\n className={`px-2 py-1 text-[10px] font-medium transition-colors flex items-center gap-1 ${\n filter === 'human'\n ? 'bg-stone-800 text-white dark:bg-white dark:text-stone-800'\n : 'text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-800'\n }`}\n >\n <User size={9} />\n {humanCount}\n </button>\n <button\n onClick={() => onFilterChange('ai')}\n className={`px-2 py-1 text-[10px] font-medium transition-colors flex items-center gap-1 ${\n filter === 'ai'\n ? 'bg-amber-600 text-white dark:bg-amber-500 dark:text-white'\n : 'text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-800'\n }`}\n >\n <Sparkles size={9} />\n {aiCount}\n </button>\n </div>\n )}\n </div>\n );\n};\n\nexport default CommentsToolbar;\n","'use client';\n\nimport React, { useState, useEffect, useLayoutEffect, useRef } from 'react';\nimport { Editor } from '@tiptap/react';\nimport {\n X,\n GitCompare,\n MessageSquare,\n CheckCheck,\n XCircle,\n MessageSquarePlus,\n} from 'lucide-react';\nimport type { Suggestion, Comment, CommentSeverity } from '../types';\nimport type { UseTrackChangesReturn } from '../hooks/useTrackChanges';\nimport type { UseCommentsReturn } from '../hooks/useComments';\nimport SuggestionItem from './SuggestionItem';\nimport CommentItem from './CommentItem';\n\nexport type ReviewTab = 'suggestions' | 'comments';\n\ntype SuggestionFilter = 'all' | 'human' | 'ai';\ntype CommentFilter = 'all' | 'open' | 'resolved';\n\ninterface ReviewPanelProps {\n activeTab: ReviewTab;\n onTabChange: (tab: ReviewTab) => void;\n onClose: () => void;\n trackChanges: UseTrackChangesReturn;\n commentsState: UseCommentsReturn;\n editor: Editor | null;\n onScrollToSuggestion?: (s: Suggestion) => void;\n onScrollToComment?: (c: Comment) => void;\n readOnly?: boolean;\n isHistoricalVersion?: boolean;\n}\n\nconst ReviewPanel: React.FC<ReviewPanelProps> = ({\n activeTab,\n onTabChange,\n onClose,\n trackChanges,\n commentsState,\n editor,\n onScrollToSuggestion,\n onScrollToComment,\n readOnly = false,\n isHistoricalVersion = false,\n}) => {\n // Suggestions state\n const [suggestionFilter, setSuggestionFilter] = useState<SuggestionFilter>('all');\n const { suggestions, acceptSuggestion, rejectSuggestion, acceptAll, rejectAll } = trackChanges;\n\n const filteredSuggestions = suggestions.filter((s) => {\n if (suggestionFilter === 'human') return !s.author.isAI;\n if (suggestionFilter === 'ai') return s.author.isAI;\n return true;\n });\n\n // Comments state\n const [commentFilter, setCommentFilter] = useState<CommentFilter>('all');\n const [commentText, setCommentText] = useState('');\n const [severity, setSeverity] = useState<CommentSeverity>('moderate');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const commentListRef = useRef<HTMLDivElement>(null);\n\n const {\n comments,\n activeCommentId,\n pendingSelectionText,\n resolveComment,\n unresolveComment,\n deleteComment,\n setSeverity: setCommentSeverity,\n addReply,\n deleteReply,\n resolveAll,\n } = commentsState;\n\n const filteredComments = comments.filter((c) => {\n if (commentFilter === 'open' && c.resolved) return false;\n if (commentFilter === 'resolved' && !c.resolved) return false;\n return true;\n });\n\n const openCount = comments.filter((c) => !c.resolved).length;\n\n // Auto-scroll to active comment\n useEffect(() => {\n if (!activeCommentId || !commentListRef.current) return;\n const el = commentListRef.current.querySelector(`[data-comment-id=\"${activeCommentId}\"]`);\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n }, [activeCommentId]);\n\n useLayoutEffect(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n textarea.style.height = '0px';\n const nextHeight = Math.min(textarea.scrollHeight, 120);\n textarea.style.height = `${Math.max(nextHeight, 40)}px`;\n }, [commentText, pendingSelectionText]);\n\n const handleSubmitComment = () => {\n const text = commentText.trim();\n if (!text) return;\n commentsState.addComment(text, severity);\n setCommentText('');\n setSeverity('moderate');\n };\n\n return (\n <div className=\"w-80 border-l border-stone-200 dark:border-stone-700 bg-stone-50 dark:bg-stone-900 flex flex-col h-full\">\n\n {/* ═══ Tab Header — Segmented Control ═══ */}\n <div className=\"flex items-center justify-between px-3 py-2.5 bg-white dark:bg-stone-900 border-b border-stone-200 dark:border-stone-700\">\n <div className=\"flex p-0.5 rounded-lg bg-stone-100 dark:bg-stone-800\">\n <button\n onClick={() => onTabChange('comments')}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-[11px] font-semibold rounded-md transition-all ${\n activeTab === 'comments'\n ? 'bg-white dark:bg-stone-700 text-stone-800 dark:text-stone-100 shadow-sm'\n : 'text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-300'\n }`}\n >\n <MessageSquare size={12} />\n Comments\n {comments.length > 0 && (\n <span className={`ml-0.5 px-1.5 py-0.5 text-[9px] font-bold rounded-full ${\n activeTab === 'comments'\n ? 'bg-stone-800 dark:bg-white text-white dark:text-stone-800'\n : 'bg-stone-200 dark:bg-stone-700 text-stone-500 dark:text-stone-400'\n }`}>\n {comments.length}\n </span>\n )}\n </button>\n <button\n onClick={() => onTabChange('suggestions')}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-[11px] font-semibold rounded-md transition-all ${\n activeTab === 'suggestions'\n ? 'bg-white dark:bg-stone-700 text-stone-800 dark:text-stone-100 shadow-sm'\n : 'text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-300'\n }`}\n >\n <GitCompare size={12} />\n Suggestions\n {suggestions.length > 0 && (\n <span className={`ml-0.5 px-1.5 py-0.5 text-[9px] font-bold rounded-full ${\n activeTab === 'suggestions'\n ? 'bg-stone-800 dark:bg-white text-white dark:text-stone-800'\n : 'bg-stone-200 dark:bg-stone-700 text-stone-500 dark:text-stone-400'\n }`}>\n {suggestions.length}\n </span>\n )}\n </button>\n </div>\n <button\n onClick={onClose}\n className=\"p-1.5 rounded-md text-stone-400 hover:text-stone-600 dark:hover:text-stone-300 hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors\"\n >\n <X size={14} />\n </button>\n </div>\n\n {/* ═══ Suggestions Tab ═══ */}\n {activeTab === 'suggestions' && (\n <>\n {/* Filter pills */}\n <div className=\"flex gap-1 px-3 py-2 bg-white dark:bg-stone-900 border-b border-stone-100 dark:border-stone-800\">\n {(['all', 'human', 'ai'] as SuggestionFilter[]).map((mode) => (\n <button\n key={mode}\n onClick={() => setSuggestionFilter(mode)}\n className={`px-2.5 py-1 text-[11px] font-medium rounded-full border transition-colors ${\n suggestionFilter === mode\n ? 'bg-stone-800 dark:bg-white text-white dark:text-stone-800 border-transparent'\n : 'text-stone-500 dark:text-stone-400 border-stone-200 dark:border-stone-700 hover:border-stone-300 dark:hover:border-stone-600'\n }`}\n >\n {mode === 'all' ? 'All' : mode === 'human' ? 'Human' : 'AI'}\n </button>\n ))}\n </div>\n\n {/* Suggestion list */}\n <div className=\"flex-1 overflow-y-auto p-3 space-y-2\">\n {filteredSuggestions.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-32 text-stone-400 dark:text-stone-500\">\n <GitCompare size={24} className=\"mb-2 opacity-40\" />\n <p className=\"text-[12px] font-medium\">No pending suggestions</p>\n </div>\n ) : (\n filteredSuggestions.map((suggestion) => (\n <SuggestionItem\n key={suggestion.id}\n suggestion={suggestion}\n onAccept={acceptSuggestion}\n onReject={rejectSuggestion}\n onScrollTo={onScrollToSuggestion}\n readOnly={readOnly}\n />\n ))\n )}\n </div>\n\n {/* Footer: Accept All / Reject All */}\n {!readOnly && suggestions.length > 0 && (\n <div className=\"flex gap-2 px-3 py-3 bg-white dark:bg-stone-900 border-t border-stone-200 dark:border-stone-700\">\n <button\n onClick={acceptAll}\n className=\"flex-1 flex items-center justify-center gap-1.5 px-3 py-2 text-[11px] font-semibold rounded-lg bg-emerald-600 text-white hover:bg-emerald-700 transition-colors\"\n >\n <CheckCheck size={13} />\n Accept All\n </button>\n <button\n onClick={rejectAll}\n className=\"flex-1 flex items-center justify-center gap-1.5 px-3 py-2 text-[11px] font-semibold rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors\"\n >\n <XCircle size={13} />\n Reject All\n </button>\n </div>\n )}\n </>\n )}\n\n {/* ═══ Comments Tab ═══ */}\n {activeTab === 'comments' && (\n <>\n {/* Filter row */}\n <div className=\"flex gap-1 px-3 py-2 bg-white dark:bg-stone-900 border-b border-stone-100 dark:border-stone-800\">\n {(['all', 'open', 'resolved'] as CommentFilter[]).map((mode) => (\n <button\n key={mode}\n onClick={() => setCommentFilter(mode)}\n className={`px-2.5 py-1 text-[11px] font-medium rounded-full border transition-colors ${\n commentFilter === mode\n ? 'bg-stone-800 dark:bg-white text-white dark:text-stone-800 border-transparent'\n : 'text-stone-500 dark:text-stone-400 border-stone-200 dark:border-stone-700 hover:border-stone-300 dark:hover:border-stone-600'\n }`}\n >\n {mode === 'all' ? `All (${comments.length})` : mode === 'open' ? `Open (${openCount})` : `Resolved (${comments.length - openCount})`}\n </button>\n ))}\n </div>\n\n {/* Composer */}\n <div className=\"px-3 py-3 bg-white dark:bg-stone-900 border-b border-stone-200 dark:border-stone-700\">\n {/* Severity selector */}\n <div className=\"flex items-center gap-1 mb-2\">\n <span className=\"text-[10px] font-semibold text-stone-400 dark:text-stone-500 uppercase tracking-wider mr-1\">Severity</span>\n {(['high', 'moderate', 'low'] as CommentSeverity[]).map((sev) => {\n const cfg = {\n high: { dot: 'bg-red-500', activeBg: 'bg-red-50 dark:bg-red-900/30 border-red-200 dark:border-red-800/40', activeText: 'text-red-700 dark:text-red-400' },\n moderate: { dot: 'bg-amber-500', activeBg: 'bg-amber-50 dark:bg-amber-900/30 border-amber-200 dark:border-amber-800/40', activeText: 'text-amber-700 dark:text-amber-400' },\n low: { dot: 'bg-blue-500', activeBg: 'bg-blue-50 dark:bg-blue-900/30 border-blue-200 dark:border-blue-800/40', activeText: 'text-blue-700 dark:text-blue-400' },\n }[sev];\n return (\n <button\n key={sev}\n onClick={() => setSeverity(sev)}\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-[10px] font-semibold rounded-full border transition-colors ${\n severity === sev\n ? `${cfg.activeBg} ${cfg.activeText}`\n : 'text-stone-400 dark:text-stone-500 border-stone-200 dark:border-stone-700 hover:border-stone-300'\n }`}\n >\n <span className={`w-1.5 h-1.5 rounded-full ${cfg.dot}`} />\n {sev.charAt(0).toUpperCase() + sev.slice(1)}\n </button>\n );\n })}\n </div>\n\n <div className=\"flex items-end gap-2\">\n <textarea\n ref={textareaRef}\n value={commentText}\n onChange={(e) => setCommentText(e.target.value)}\n onMouseDown={() => commentsState.captureSelection()}\n onBlur={() => { if (!commentText.trim()) commentsState.clearPendingHighlight(); }}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault();\n handleSubmitComment();\n }\n }}\n placeholder={pendingSelectionText ? 'Write your comment...' : 'Select text to comment'}\n rows={1}\n className=\"max-h-[120px] min-h-10 flex-1 resize-none overflow-y-auto rounded-lg border border-stone-200 dark:border-stone-700 bg-stone-50 dark:bg-stone-800 px-3 py-2 text-[12px] leading-5 text-stone-700 dark:text-stone-200 outline-none focus:ring-1 focus:ring-stone-400 dark:focus:ring-stone-600 placeholder:text-stone-400 dark:placeholder:text-stone-500\"\n />\n <button\n onClick={handleSubmitComment}\n disabled={!pendingSelectionText || !commentText.trim()}\n title=\"Add comment (Cmd+Enter)\"\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-lg bg-stone-800 dark:bg-white text-white dark:text-stone-800 transition-colors hover:bg-stone-700 dark:hover:bg-stone-200 disabled:cursor-not-allowed disabled:opacity-30\"\n >\n <MessageSquarePlus size={14} />\n </button>\n </div>\n </div>\n\n {/* Historical version banner */}\n {isHistoricalVersion && (\n <div className=\"mx-3 mt-2 px-3 py-2 rounded-lg bg-stone-100 dark:bg-stone-800/60 border border-stone-200 dark:border-stone-700\">\n <p className=\"text-[11px] text-stone-500 dark:text-stone-400 leading-snug\">\n Viewing a past version — comments are read-only. Open the latest version to add or reply to comments.\n </p>\n </div>\n )}\n\n {/* Comment list */}\n <div ref={commentListRef} className=\"flex-1 overflow-y-auto px-3 py-3 space-y-2.5\">\n {filteredComments.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-32 text-stone-400 dark:text-stone-500\">\n <MessageSquare size={24} className=\"mb-2 opacity-40\" />\n <p className=\"text-[12px] font-medium\">\n {comments.length === 0 ? 'No comments yet' : 'No matching comments'}\n </p>\n </div>\n ) : (\n filteredComments.map((comment) => (\n <div key={comment.id} data-comment-id={comment.id}>\n <CommentItem\n comment={comment}\n isActive={activeCommentId === comment.id}\n onResolve={resolveComment}\n onUnresolve={unresolveComment}\n onDelete={deleteComment}\n onSetSeverity={setCommentSeverity}\n onAddReply={addReply}\n onDeleteReply={deleteReply}\n onScrollTo={onScrollToComment}\n readOnly={readOnly}\n isHistoricalVersion={isHistoricalVersion}\n />\n </div>\n ))\n )}\n </div>\n\n {/* Footer: Resolve All */}\n {!readOnly && !isHistoricalVersion && openCount > 0 && (\n <div className=\"px-3 py-3 bg-white dark:bg-stone-900 border-t border-stone-200 dark:border-stone-700\">\n <button\n onClick={resolveAll}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 text-[12px] font-semibold rounded-lg bg-emerald-600 text-white hover:bg-emerald-700 shadow-sm transition-all hover:shadow-md\"\n >\n <CheckCheck size={14} />\n Resolve All ({openCount})\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n};\n\nexport default ReviewPanel;\n","'use client';\n\nimport React from 'react';\nimport { Check, X, Sparkles, User } from 'lucide-react';\nimport type { Suggestion } from '../types';\n\ninterface SuggestionItemProps {\n suggestion: Suggestion;\n onAccept: (s: Suggestion) => void;\n onReject: (s: Suggestion) => void;\n onScrollTo?: (s: Suggestion) => void;\n /** Hide accept/reject buttons (e.g. for reviewers) */\n readOnly?: boolean;\n}\n\nconst SuggestionItem: React.FC<SuggestionItemProps> = ({\n suggestion,\n onAccept,\n onReject,\n onScrollTo,\n readOnly = false,\n}) => {\n const isInsertion = suggestion.type === 'insertion';\n\n return (\n <div\n className=\"p-3 border border-stone-200 dark:border-stone-700 rounded-lg hover:bg-stone-50 dark:hover:bg-stone-800/50 transition-colors cursor-pointer\"\n onClick={() => onScrollTo?.(suggestion)}\n >\n {/* Header: author + type badge */}\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"flex items-center gap-2\">\n {suggestion.author.isAI ? (\n <Sparkles size={14} className=\"text-violet-500\" />\n ) : (\n <User size={14} className=\"text-stone-400\" />\n )}\n <span className=\"text-xs font-medium text-stone-600 dark:text-stone-400\">\n {suggestion.author.username}\n </span>\n </div>\n <span\n className={`text-[10px] font-semibold uppercase px-1.5 py-0.5 rounded ${\n isInsertion\n ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400'\n : 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400'\n }`}\n >\n {isInsertion ? 'Insert' : 'Delete'}\n </span>\n </div>\n\n {/* Text preview */}\n <p\n className={`text-sm mb-3 line-clamp-2 ${\n isInsertion\n ? 'text-green-700 dark:text-green-400'\n : 'text-red-700 dark:text-red-400 line-through'\n }`}\n >\n {suggestion.text}\n </p>\n\n {/* Reason (from AI data) */}\n {suggestion.data?.reason && (\n <p className=\"text-xs text-stone-500 dark:text-stone-400 mb-2 italic\">\n {suggestion.data.reason}\n </p>\n )}\n\n {/* Accept / Reject buttons — hidden for reviewers */}\n {!readOnly && (\n <div className=\"flex items-center gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n onAccept(suggestion);\n }}\n className=\"flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-md bg-green-600 text-white hover:bg-green-700 transition-colors\"\n >\n <Check size={12} />\n Accept\n </button>\n <button\n onClick={(e) => {\n e.stopPropagation();\n onReject(suggestion);\n }}\n className=\"flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-md bg-red-600 text-white hover:bg-red-700 transition-colors\"\n >\n <X size={12} />\n Reject\n </button>\n </div>\n )}\n </div>\n );\n};\n\nexport default SuggestionItem;\n","'use client';\n\nimport React, { useState } from 'react';\nimport { Check, Trash2, User, Send, RotateCcw, Sparkles, Lock, MessageSquare } from 'lucide-react';\nimport type { Comment, CommentSeverity } from '../types';\n\nconst SEVERITY_CONFIG: Record<CommentSeverity, { label: string; bg: string; text: string; dot: string; border: string }> = {\n high: {\n label: 'High',\n bg: 'bg-red-50 dark:bg-red-950/20',\n text: 'text-red-700 dark:text-red-400',\n dot: 'bg-red-500',\n border: 'border-l-red-500',\n },\n moderate: {\n label: 'Moderate',\n bg: 'bg-amber-50 dark:bg-amber-950/20',\n text: 'text-amber-700 dark:text-amber-400',\n dot: 'bg-amber-500',\n border: 'border-l-amber-500',\n },\n low: {\n label: 'Low',\n bg: 'bg-blue-50 dark:bg-blue-950/20',\n text: 'text-blue-700 dark:text-blue-400',\n dot: 'bg-blue-500',\n border: 'border-l-blue-500',\n },\n};\n\ninterface CommentItemProps {\n comment: Comment;\n isActive: boolean;\n onResolve: (commentId: string) => void;\n onUnresolve: (commentId: string) => void;\n onDelete: (commentId: string) => void;\n onSetSeverity: (commentId: string, severity: CommentSeverity) => void;\n onAddReply: (commentId: string, text: string) => void;\n onDeleteReply: (commentId: string, replyId: string) => void;\n onScrollTo?: (comment: Comment) => void;\n readOnly?: boolean;\n isHistoricalVersion?: boolean;\n}\n\nfunction timeAgo(dateStr: string): string {\n const now = Date.now();\n const then = new Date(dateStr).getTime();\n const diff = Math.floor((now - then) / 1000);\n if (diff < 60) return 'just now';\n if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;\n if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;\n return `${Math.floor(diff / 86400)}d ago`;\n}\n\n/**\n * Render comment body text with basic markdown-like formatting.\n * Handles **bold**, *italic*, and `code` inline markers.\n */\nfunction renderFormattedText(text: string): React.ReactNode {\n // Split by **bold**, *italic*, `code` patterns\n const parts: React.ReactNode[] = [];\n const regex = /(\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|`(.+?)`)/g;\n let lastIndex = 0;\n let match;\n let key = 0;\n\n while ((match = regex.exec(text)) !== null) {\n // Text before the match\n if (match.index > lastIndex) {\n parts.push(text.slice(lastIndex, match.index));\n }\n if (match[2]) {\n // **bold**\n parts.push(<strong key={key++} className=\"font-semibold text-stone-800 dark:text-stone-200\">{match[2]}</strong>);\n } else if (match[3]) {\n // *italic*\n parts.push(<em key={key++}>{match[3]}</em>);\n } else if (match[4]) {\n // `code`\n parts.push(<code key={key++} className=\"px-1 py-0.5 rounded bg-stone-100 dark:bg-stone-800 text-[11px] font-mono\">{match[4]}</code>);\n }\n lastIndex = match.index + match[0].length;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts.length > 0 ? parts : text;\n}\n\n/**\n * Split comment body into main text and recommendation block.\n * Looks for \"Recommendation:\" or \"**Recommendation:**\" pattern.\n */\nfunction splitRecommendation(text: string): { body: string; recommendation: string | null } {\n const match = text.match(/\\*{0,2}Recommendation:\\*{0,2}\\s*([\\s\\S]*)/i);\n if (match) {\n const body = text.slice(0, match.index).trim();\n const recommendation = match[1].trim();\n return { body, recommendation };\n }\n return { body: text, recommendation: null };\n}\n\nconst CommentItem: React.FC<CommentItemProps> = ({\n comment,\n isActive,\n onResolve,\n onUnresolve,\n onDelete,\n onSetSeverity,\n onAddReply,\n onDeleteReply,\n onScrollTo,\n readOnly = false,\n isHistoricalVersion = false,\n}) => {\n const [replyText, setReplyText] = useState('');\n const [showReplyInput, setShowReplyInput] = useState(false);\n const severity = comment.severity || 'moderate';\n const sev = SEVERITY_CONFIG[severity];\n const isAI = comment.author.isAI;\n const isFullyReadOnly = readOnly || isHistoricalVersion;\n const { body, recommendation } = splitRecommendation(comment.text);\n\n const handleSubmitReply = () => {\n if (!replyText.trim()) return;\n onAddReply(comment.id, replyText.trim());\n setReplyText('');\n setShowReplyInput(false);\n };\n\n const cycleSeverity = () => {\n const order: CommentSeverity[] = ['low', 'moderate', 'high'];\n const idx = order.indexOf(severity);\n const next = order[(idx + 1) % order.length];\n onSetSeverity(comment.id, next);\n };\n\n return (\n <div\n data-testid={isAI ? 'ai-comment' : 'human-comment'}\n className={`\n rounded-lg border-l-[3px] ${sev.border} transition-all duration-150 cursor-pointer\n ${isActive\n ? 'bg-white dark:bg-stone-800/70 shadow-md ring-1 ring-stone-200 dark:ring-stone-700'\n : 'bg-white dark:bg-stone-900 shadow-sm hover:shadow-md hover:ring-1 hover:ring-stone-200 dark:hover:ring-stone-700'\n }\n ${comment.resolved ? 'opacity-50' : ''}\n ${isAI ? 'border-l-indigo-500' : ''}\n `}\n onClick={() => onScrollTo?.(comment)}\n >\n {/* ── Header ── */}\n <div className=\"flex items-center justify-between px-3.5 pt-3 pb-2\">\n <div className=\"flex items-center gap-2 min-w-0\">\n {isAI ? (\n <div className=\"w-6 h-6 rounded-full bg-indigo-100 dark:bg-indigo-900/30 flex items-center justify-center flex-shrink-0\">\n <Sparkles size={12} className=\"text-indigo-600 dark:text-indigo-400\" />\n </div>\n ) : (\n <div className=\"w-6 h-6 rounded-full bg-stone-100 dark:bg-stone-800 flex items-center justify-center flex-shrink-0\">\n <span className=\"text-[10px] font-bold text-stone-500 dark:text-stone-400\">\n {comment.author.username.charAt(0).toUpperCase()}\n </span>\n </div>\n )}\n <div className=\"min-w-0\">\n <span className={`text-[12px] font-semibold truncate block ${isAI ? 'text-indigo-700 dark:text-indigo-400' : 'text-stone-700 dark:text-stone-300'}`}>\n {isAI ? 'AI Review' : comment.author.username}\n </span>\n </div>\n <span className=\"text-[10px] text-stone-400 dark:text-stone-500 flex-shrink-0\">\n {timeAgo(comment.createdAt)}\n </span>\n {isHistoricalVersion && (\n <Lock size={10} className=\"text-stone-300 dark:text-stone-600 flex-shrink-0\" />\n )}\n </div>\n <div className=\"flex items-center gap-1.5 flex-shrink-0\">\n {/* Severity pill */}\n {!comment.resolved && (\n <button\n onClick={(e) => { e.stopPropagation(); if (!isFullyReadOnly) cycleSeverity(); }}\n disabled={isFullyReadOnly}\n className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold transition-colors ${sev.bg} ${sev.text} ${!isFullyReadOnly ? 'hover:opacity-80 cursor-pointer' : 'cursor-default'}`}\n title={isFullyReadOnly ? sev.label : `Severity: ${sev.label} (click to change)`}\n >\n <span className={`w-1.5 h-1.5 rounded-full ${sev.dot}`} />\n {sev.label}\n </button>\n )}\n {comment.resolved && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-emerald-50 text-emerald-700 dark:bg-emerald-900/20 dark:text-emerald-400\">\n <Check size={10} />\n Resolved\n </span>\n )}\n </div>\n </div>\n\n {/* ── Quoted clause ── */}\n {comment.selectedText && (\n <div className=\"mx-3.5 mb-2.5 px-3 py-2 rounded-md bg-stone-50 dark:bg-stone-800/50 border-l-2 border-stone-300 dark:border-stone-600\">\n <p className=\"text-[11px] text-stone-500 dark:text-stone-400 leading-relaxed italic line-clamp-3\">\n &ldquo;{comment.selectedText}&rdquo;\n </p>\n </div>\n )}\n\n {/* ── Comment body ── */}\n <div className=\"px-3.5 pb-2\">\n <div className=\"text-[13px] text-stone-700 dark:text-stone-300 leading-relaxed\">\n {renderFormattedText(body)}\n </div>\n </div>\n\n {/* ── Recommendation block ── */}\n {recommendation && (\n <div className=\"mx-3.5 mb-2.5 px-3 py-2 rounded-md bg-amber-50/70 dark:bg-amber-950/15 border border-amber-200/50 dark:border-amber-800/30\">\n <p className=\"text-[10px] font-semibold text-amber-700 dark:text-amber-400 uppercase tracking-wider mb-0.5\">\n Recommendation\n </p>\n <p className=\"text-[12px] text-amber-900 dark:text-amber-200 leading-relaxed\">\n {renderFormattedText(recommendation)}\n </p>\n </div>\n )}\n\n {/* ── Replies ── */}\n {comment.replies.length > 0 && (\n <div className=\"mx-3.5 mb-2 pt-2 border-t border-stone-100 dark:border-stone-800 space-y-2\">\n {comment.replies.map((reply) => (\n <div key={reply.id} className=\"flex gap-2 group\">\n <div className=\"w-5 h-5 rounded-full bg-stone-100 dark:bg-stone-800 flex items-center justify-center flex-shrink-0 mt-0.5\">\n <span className=\"text-[8px] font-bold text-stone-500 dark:text-stone-400\">\n {reply.author.username.charAt(0).toUpperCase()}\n </span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5 mb-0.5\">\n <span className=\"text-[11px] font-medium text-stone-600 dark:text-stone-400\">\n {reply.author.username}\n </span>\n <span className=\"text-[9px] text-stone-400 dark:text-stone-500\">\n {timeAgo(reply.createdAt)}\n </span>\n {!isFullyReadOnly && (\n <button\n onClick={(e) => { e.stopPropagation(); onDeleteReply(comment.id, reply.id); }}\n className=\"ml-auto opacity-0 group-hover:opacity-100 p-0.5 rounded text-stone-400 hover:text-red-500 transition-all\"\n title=\"Delete reply\"\n >\n <Trash2 size={9} />\n </button>\n )}\n </div>\n <p className=\"text-[12px] text-stone-600 dark:text-stone-400 leading-relaxed\">\n {renderFormattedText(reply.text)}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* ── Reply input ── */}\n {showReplyInput && !isHistoricalVersion && (\n <div className=\"mx-3.5 mb-2 flex items-center gap-1.5\" onClick={(e) => e.stopPropagation()}>\n <input\n type=\"text\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleSubmitReply();\n if (e.key === 'Escape') { setShowReplyInput(false); setReplyText(''); }\n }}\n placeholder=\"Write a reply...\"\n className=\"flex-1 px-2.5 py-1.5 text-[12px] rounded-md border border-stone-200 dark:border-stone-700 bg-stone-50 dark:bg-stone-800 text-stone-700 dark:text-stone-300 outline-none focus:ring-1 focus:ring-stone-400 dark:focus:ring-stone-600 placeholder:text-stone-400\"\n autoFocus\n />\n <button\n onClick={handleSubmitReply}\n disabled={!replyText.trim()}\n className=\"p-1.5 rounded-md bg-stone-800 dark:bg-white text-white dark:text-stone-800 hover:bg-stone-700 dark:hover:bg-stone-200 disabled:opacity-30 transition-colors\"\n >\n <Send size={12} />\n </button>\n </div>\n )}\n\n {/* ── Actions ── */}\n {!isHistoricalVersion && (\n <div className=\"flex items-center gap-0.5 px-2 pb-2\">\n {!isFullyReadOnly && !comment.resolved && (\n <button\n onClick={(e) => { e.stopPropagation(); onResolve(comment.id); }}\n className=\"flex items-center gap-1 px-2 py-1 text-[11px] font-medium rounded-md text-emerald-600 hover:bg-emerald-50 dark:hover:bg-emerald-900/20 transition-colors\"\n >\n <Check size={11} />\n Resolve\n </button>\n )}\n {!isFullyReadOnly && comment.resolved && (\n <button\n onClick={(e) => { e.stopPropagation(); onUnresolve(comment.id); }}\n className=\"flex items-center gap-1 px-2 py-1 text-[11px] font-medium rounded-md text-amber-600 hover:bg-amber-50 dark:hover:bg-amber-900/20 transition-colors\"\n >\n <RotateCcw size={11} />\n Reopen\n </button>\n )}\n <button\n onClick={(e) => { e.stopPropagation(); setShowReplyInput(!showReplyInput); }}\n className=\"flex items-center gap-1 px-2 py-1 text-[11px] font-medium rounded-md text-stone-500 hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors\"\n >\n <MessageSquare size={10} />\n Reply\n </button>\n {!isFullyReadOnly && (\n <button\n onClick={(e) => { e.stopPropagation(); onDelete(comment.id); }}\n className=\"ml-auto p-1 rounded-md text-stone-300 dark:text-stone-600 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\n title=\"Delete\"\n >\n <Trash2 size={11} />\n </button>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default React.memo(CommentItem);\n","'use client';\n\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { Editor } from '@tiptap/react';\nimport { MessageSquarePlus, Send, X } from 'lucide-react';\nimport type { UseCommentsReturn } from '../hooks/useComments';\nimport type { CommentSeverity } from '../types';\n\ninterface BubblePosition {\n top: number;\n left: number;\n}\n\ninterface SelectionCommentBubbleProps {\n editor: Editor | null;\n comments: UseCommentsReturn;\n}\n\nexport const SelectionCommentBubble: React.FC<SelectionCommentBubbleProps> = ({\n editor,\n comments,\n}) => {\n const [position, setPosition] = useState<BubblePosition | null>(null);\n const [expanded, setExpanded] = useState(false);\n const [text, setText] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [severity, setSeverity] = useState<CommentSeverity>('moderate');\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const bubbleRef = useRef<HTMLDivElement>(null);\n\n // Calculate bubble position from the current selection\n const updatePosition = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n if (from === to) {\n setPosition(null);\n setExpanded(false);\n return;\n }\n\n try {\n // Use the end of the selection to anchor the bubble\n const startCoords = editor.view.coordsAtPos(from);\n const endCoords = editor.view.coordsAtPos(to);\n\n // Center horizontally across the selection, place just above the top line\n const midX = (startCoords.left + endCoords.left) / 2;\n const topY = Math.min(startCoords.top, endCoords.top);\n\n setPosition({\n // 44px above the selection top so the bubble sits above text\n top: topY - 44,\n left: midX,\n });\n } catch {\n // coordsAtPos can throw for out-of-range positions — ignore\n }\n }, [editor]);\n\n // Listen for selection changes\n useEffect(() => {\n if (!editor) return;\n editor.on('selectionUpdate', updatePosition);\n // Also handle when editor loses focus — hide bubble if no expanded composer\n const handleBlur = () => {\n if (!expanded) {\n setPosition(null);\n }\n };\n editor.on('blur', handleBlur);\n return () => {\n editor.off('selectionUpdate', updatePosition);\n editor.off('blur', handleBlur);\n };\n }, [editor, updatePosition, expanded]);\n\n // Focus input when composer opens\n useEffect(() => {\n if (expanded && inputRef.current) {\n // Short delay to let the DOM settle\n setTimeout(() => inputRef.current?.focus(), 50);\n }\n }, [expanded]);\n\n // Close on Escape\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && expanded) {\n handleClose();\n }\n };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [expanded]);\n\n const handleClose = () => {\n setExpanded(false);\n setText('');\n setSeverity('moderate');\n comments.clearPendingHighlight?.();\n // Restore focus to editor\n editor?.commands.focus();\n };\n\n const handleOpen = () => {\n if (!editor) return;\n // Capture selection NOW before focus moves to the textarea\n comments.captureSelection();\n setExpanded(true);\n };\n\n const handleSubmit = async () => {\n const trimmed = text.trim();\n if (!trimmed || submitting) return;\n setSubmitting(true);\n try {\n comments.addComment(trimmed, severity);\n setText('');\n setExpanded(false);\n setPosition(null);\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleSubmit();\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n handleClose();\n }\n };\n\n if (!position) return null;\n\n return (\n <div\n ref={bubbleRef}\n style={{\n position: 'fixed',\n top: position.top,\n left: position.left,\n transform: 'translateX(-50%)',\n zIndex: 9999,\n }}\n // Stop pointer events from propagating to the editor (avoids clearing selection)\n onMouseDown={(e) => e.stopPropagation()}\n >\n {!expanded ? (\n // ── Compact trigger button ──\n <button\n onMouseDown={(e) => {\n e.preventDefault(); // critical: don't steal focus / clear selection\n handleOpen();\n }}\n className=\"\n flex items-center gap-1.5 px-2.5 py-1.5 rounded-full\n bg-white dark:bg-[#1e1e1e]\n border border-stone-200 dark:border-stone-700\n shadow-md shadow-black/10 dark:shadow-black/30\n text-[12px] font-medium text-stone-600 dark:text-stone-300\n hover:bg-stone-50 dark:hover:bg-stone-800\n hover:border-stone-300 dark:hover:border-stone-600\n transition-all duration-150\n select-none\n \"\n title=\"Add comment (⌘ + Enter to submit)\"\n >\n <MessageSquarePlus size={13} className=\"text-amber-500 flex-shrink-0\" />\n <span>Comment</span>\n </button>\n ) : (\n // ── Expanded composer ──\n <div\n className=\"\n w-72 rounded-xl overflow-hidden\n bg-white dark:bg-[#1e1e1e]\n border border-stone-200 dark:border-stone-700\n shadow-xl shadow-black/10 dark:shadow-black/40\n \"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-stone-100 dark:border-stone-800\">\n <div className=\"flex items-center gap-1.5\">\n <MessageSquarePlus size={12} className=\"text-amber-500\" />\n <span className=\"text-[11px] font-semibold text-stone-600 dark:text-stone-400 uppercase tracking-wider\">\n Add comment\n </span>\n </div>\n <button\n onMouseDown={(e) => { e.preventDefault(); handleClose(); }}\n className=\"p-0.5 rounded text-stone-300 hover:text-stone-500 dark:text-stone-600 dark:hover:text-stone-400 transition-colors\"\n >\n <X size={12} />\n </button>\n </div>\n\n {/* Input */}\n <div className=\"px-3 pt-2.5 pb-2\">\n <textarea\n ref={inputRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Add a comment…\"\n rows={3}\n className=\"\n w-full resize-none text-[13px] leading-relaxed\n text-stone-800 dark:text-stone-200\n placeholder:text-stone-300 dark:placeholder:text-stone-600\n bg-transparent outline-none\n \"\n />\n </div>\n\n {/* Severity selector */}\n <div className=\"flex items-center gap-1.5 px-3 pb-2.5\">\n {([\n { value: 'high', label: 'High', dot: 'bg-red-500', active: 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 border-red-200 dark:border-red-800/40', inactive: 'text-stone-400 dark:text-stone-500 border-stone-200 dark:border-stone-700 hover:bg-stone-50 dark:hover:bg-stone-800' },\n { value: 'moderate', label: 'Moderate', dot: 'bg-amber-500', active: 'bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-800/40', inactive: 'text-stone-400 dark:text-stone-500 border-stone-200 dark:border-stone-700 hover:bg-stone-50 dark:hover:bg-stone-800' },\n { value: 'low', label: 'Low', dot: 'bg-blue-500', active: 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-800/40', inactive: 'text-stone-400 dark:text-stone-500 border-stone-200 dark:border-stone-700 hover:bg-stone-50 dark:hover:bg-stone-800' },\n ] as const).map(({ value, label, dot, active, inactive }) => (\n <button\n key={value}\n onMouseDown={(e) => { e.preventDefault(); setSeverity(value); }}\n className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full border text-[10px] font-medium transition-colors ${severity === value ? active : inactive}`}\n >\n <span className={`w-1.5 h-1.5 rounded-full flex-shrink-0 ${dot}`} />\n {label}\n </button>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-between px-3 py-2 bg-stone-50/60 dark:bg-white/[0.02] border-t border-stone-100 dark:border-stone-800/60\">\n <span className=\"text-[10px] text-stone-300 dark:text-stone-600 select-none\">\n ⌘↵ to submit\n </span>\n <div className=\"flex items-center gap-1.5\">\n <button\n onMouseDown={(e) => { e.preventDefault(); handleClose(); }}\n className=\"px-2.5 py-1 rounded-md text-[11px] font-medium text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors\"\n >\n Cancel\n </button>\n <button\n onMouseDown={(e) => { e.preventDefault(); handleSubmit(); }}\n disabled={!text.trim() || submitting}\n className=\"\n inline-flex items-center gap-1 px-2.5 py-1 rounded-md\n text-[11px] font-medium text-white\n bg-[#111111] dark:bg-white dark:text-[#111111]\n hover:bg-[#333] dark:hover:bg-stone-200\n disabled:opacity-40 transition-colors\n \"\n >\n <Send size={10} />\n Save\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default SelectionCommentBubble;\n","'use client';\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { Check, Trash2, User, Send, RotateCcw, X, Sparkles, Lock } from 'lucide-react';\nimport type { Comment, CommentSeverity } from '../types';\nimport type { UseCommentsReturn } from '../hooks/useComments';\n\nconst SEVERITY_COLORS: Record<CommentSeverity, string> = {\n high: 'bg-red-500',\n moderate: 'bg-amber-500',\n low: 'bg-blue-500',\n};\n\nconst SEVERITY_LABELS: Record<CommentSeverity, string> = {\n high: 'High',\n moderate: 'Moderate',\n low: 'Low',\n};\n\ninterface InlineCommentPopoverProps {\n comment: Comment;\n position: { top: number; left: number };\n comments: UseCommentsReturn;\n onClose: () => void;\n readOnly?: boolean;\n isHistoricalVersion?: boolean;\n}\n\nfunction timeAgo(dateStr: string): string {\n const now = Date.now();\n const then = new Date(dateStr).getTime();\n const diff = Math.floor((now - then) / 1000);\n if (diff < 60) return 'just now';\n if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;\n if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;\n return `${Math.floor(diff / 86400)}d ago`;\n}\n\nconst InlineCommentPopover: React.FC<InlineCommentPopoverProps> = ({\n comment,\n position,\n comments,\n onClose,\n readOnly = false,\n isHistoricalVersion = false,\n}) => {\n const [replyText, setReplyText] = useState('');\n const [showReplyInput, setShowReplyInput] = useState(false);\n const popoverRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const isAI = comment.author.isAI;\n const isFullyReadOnly = readOnly || isHistoricalVersion;\n const severity = comment.severity || 'moderate';\n\n // Close on click outside\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) {\n // Don't close if clicking on another comment highlight — let the new click handler take over\n const target = e.target as HTMLElement;\n if (target.closest('.comment-highlight') || target.classList.contains('comment-dot')) return;\n onClose();\n }\n };\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [onClose]);\n\n // Focus reply input when shown\n useEffect(() => {\n if (showReplyInput && inputRef.current) {\n inputRef.current.focus();\n }\n }, [showReplyInput]);\n\n const handleSubmitReply = useCallback(() => {\n if (!replyText.trim()) return;\n comments.addReply(comment.id, replyText.trim());\n setReplyText('');\n setShowReplyInput(false);\n }, [replyText, comments, comment.id]);\n\n const cycleSeverity = () => {\n const order: CommentSeverity[] = ['low', 'moderate', 'high'];\n const idx = order.indexOf(severity);\n const next = order[(idx + 1) % order.length];\n comments.setSeverity(comment.id, next);\n };\n\n return (\n <div\n ref={popoverRef}\n style={{\n position: 'fixed',\n top: position.top + 8,\n left: position.left,\n zIndex: 9999,\n maxWidth: 360,\n minWidth: 300,\n }}\n className=\"animate-in fade-in slide-in-from-top-1 duration-150\"\n onMouseDown={(e) => e.stopPropagation()}\n >\n <div className=\"rounded-xl overflow-hidden bg-white dark:bg-[#1e1e1e] border border-stone-200 dark:border-stone-700 shadow-xl shadow-black/10 dark:shadow-black/40\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-3.5 py-2.5 border-b border-stone-100 dark:border-stone-800\">\n <div className=\"flex items-center gap-2\">\n {isAI ? (\n <Sparkles size={13} className=\"text-amber-500\" />\n ) : (\n <div className=\"w-6 h-6 rounded-full bg-stone-200 dark:bg-stone-700 flex items-center justify-center\">\n <span className=\"text-[10px] font-semibold text-stone-600 dark:text-stone-300\">\n {comment.author.username.charAt(0).toUpperCase()}\n </span>\n </div>\n )}\n <div>\n <span className={`text-[12px] font-semibold ${isAI ? 'text-amber-700 dark:text-amber-400' : 'text-stone-700 dark:text-stone-200'}`}>\n {isAI ? 'AI Review' : comment.author.username}\n </span>\n <span className=\"text-[10px] text-stone-400 dark:text-stone-500 ml-2\">\n {timeAgo(comment.createdAt)}\n </span>\n </div>\n </div>\n <div className=\"flex items-center gap-1.5\">\n {!isFullyReadOnly && !comment.resolved && (\n <button\n onClick={cycleSeverity}\n title={`Severity: ${SEVERITY_LABELS[severity]}`}\n className=\"flex items-center gap-1\"\n >\n <span className={`w-2 h-2 rounded-full ${SEVERITY_COLORS[severity]}`} />\n <span className=\"text-[10px] text-stone-400\">{SEVERITY_LABELS[severity]}</span>\n </button>\n )}\n {isHistoricalVersion && (\n <Lock size={11} className=\"text-stone-300 dark:text-stone-600\" />\n )}\n <button\n onClick={onClose}\n className=\"p-0.5 rounded text-stone-300 hover:text-stone-500 dark:text-stone-600 dark:hover:text-stone-400 transition-colors\"\n >\n <X size={13} />\n </button>\n </div>\n </div>\n\n {/* Quoted text */}\n {comment.selectedText && (\n <div className=\"mx-3.5 mt-2.5 px-2.5 py-1.5 rounded-md bg-stone-50 dark:bg-stone-800/50 border-l-2 border-stone-300 dark:border-stone-600\">\n <p className=\"text-[11px] text-stone-500 dark:text-stone-400 line-clamp-2 italic leading-relaxed\">\n &ldquo;{comment.selectedText}&rdquo;\n </p>\n </div>\n )}\n\n {/* Comment body */}\n <div className=\"px-3.5 py-2.5\">\n <p className=\"text-[13px] text-stone-700 dark:text-stone-300 leading-relaxed\">\n {comment.text}\n </p>\n </div>\n\n {/* Resolved badge */}\n {comment.resolved && (\n <div className=\"px-3.5 pb-2\">\n <span className=\"text-[10px] font-semibold uppercase px-1.5 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400\">\n Resolved\n </span>\n </div>\n )}\n\n {/* Replies */}\n {comment.replies.length > 0 && (\n <div className=\"mx-3.5 mb-2 border-t border-stone-100 dark:border-stone-800 pt-2 space-y-2\">\n {comment.replies.map((reply) => (\n <div key={reply.id} className=\"flex gap-2 group\">\n <div className=\"w-5 h-5 rounded-full bg-stone-100 dark:bg-stone-800 flex items-center justify-center flex-shrink-0 mt-0.5\">\n <span className=\"text-[9px] font-semibold text-stone-500 dark:text-stone-400\">\n {reply.author.username.charAt(0).toUpperCase()}\n </span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] font-medium text-stone-600 dark:text-stone-400\">\n {reply.author.username}\n </span>\n <span className=\"text-[9px] text-stone-400 dark:text-stone-500\">\n {timeAgo(reply.createdAt)}\n </span>\n {!isFullyReadOnly && (\n <button\n onClick={() => comments.deleteReply(comment.id, reply.id)}\n className=\"ml-auto opacity-0 group-hover:opacity-100 p-0.5 rounded text-stone-400 hover:text-red-500 transition-all\"\n >\n <Trash2 size={9} />\n </button>\n )}\n </div>\n <p className=\"text-[12px] text-stone-600 dark:text-stone-400 leading-relaxed\">\n {reply.text}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Reply input */}\n {!isHistoricalVersion && showReplyInput && (\n <div className=\"px-3.5 pb-2.5\">\n <div className=\"flex items-center gap-1.5\">\n <input\n ref={inputRef}\n type=\"text\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleSubmitReply();\n if (e.key === 'Escape') {\n setShowReplyInput(false);\n setReplyText('');\n }\n }}\n placeholder=\"Write a reply...\"\n className=\"flex-1 px-2.5 py-1.5 text-[12px] rounded-lg border border-stone-200 dark:border-stone-700 bg-white dark:bg-stone-800 text-stone-700 dark:text-stone-300 outline-none focus:ring-1 focus:ring-stone-400 dark:focus:ring-stone-600 placeholder:text-stone-300 dark:placeholder:text-stone-600\"\n />\n <button\n onClick={handleSubmitReply}\n disabled={!replyText.trim()}\n className=\"p-1.5 rounded-lg bg-[#111111] dark:bg-white text-white dark:text-[#111111] disabled:opacity-30 hover:bg-[#333] dark:hover:bg-stone-200 transition-colors\"\n >\n <Send size={12} />\n </button>\n </div>\n </div>\n )}\n\n {/* Actions footer */}\n {!isHistoricalVersion && (\n <div className=\"flex items-center gap-1 px-3 py-2 bg-stone-50/80 dark:bg-white/[0.02] border-t border-stone-100 dark:border-stone-800/60\">\n {!isFullyReadOnly && !comment.resolved && (\n <button\n onClick={() => { comments.resolveComment(comment.id); onClose(); }}\n className=\"flex items-center gap-1 px-2 py-1 text-[11px] font-medium rounded-md text-green-600 hover:bg-green-50 dark:hover:bg-green-900/20 transition-colors\"\n >\n <Check size={11} />\n Resolve\n </button>\n )}\n {!isFullyReadOnly && comment.resolved && (\n <button\n onClick={() => comments.unresolveComment(comment.id)}\n className=\"flex items-center gap-1 px-2 py-1 text-[11px] font-medium rounded-md text-amber-600 hover:bg-amber-50 dark:hover:bg-amber-900/20 transition-colors\"\n >\n <RotateCcw size={11} />\n Reopen\n </button>\n )}\n <button\n onClick={() => setShowReplyInput(!showReplyInput)}\n className=\"px-2 py-1 text-[11px] font-medium rounded-md text-stone-500 hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors\"\n >\n Reply\n </button>\n {!isFullyReadOnly && (\n <button\n onClick={() => { comments.deleteComment(comment.id); onClose(); }}\n className=\"ml-auto p-1 rounded-md text-stone-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors\"\n title=\"Delete comment\"\n >\n <Trash2 size={11} />\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default InlineCommentPopover;\n","'use client';\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport {\n Send,\n X,\n Loader2,\n Sparkles,\n AlertCircle,\n RefreshCw,\n Plus,\n History,\n HelpCircle,\n Check,\n ChevronDown,\n ChevronRight,\n} from 'lucide-react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { useI18n } from '../i18n';\nimport type {\n UseEditorAgentReturn,\n AgentToolProgress,\n AgentChatMessage,\n} from '../hooks/useEditorAgent';\nimport type { ProviderName, AgentChange } from '../agent/types';\n\nconst mdRemarkPlugins = [remarkGfm];\n\nconst mdComponents = {\n a: ({ href, children, ...props }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => {\n const isExternal = href && !href.startsWith('#');\n return (\n <a\n href={href}\n {...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}\n {...props}\n >\n {children}\n </a>\n );\n },\n};\n\n/**\n * Models the user can switch between. Production currently runs only Gemini\n * variants; the underlying `ProviderName` set still supports Anthropic + OpenAI\n * if we re-expose them later. Add a new entry here to expose another model.\n */\ninterface ModelOption {\n /** Stable id used in the dropdown's `<option value>`. */\n id: string;\n /** User-facing label in the picker. */\n label: string;\n provider: ProviderName;\n /** Model id passed verbatim to the LLM proxy + cost endpoint. */\n model: string;\n}\n\nconst MODEL_OPTIONS: ModelOption[] = [\n { id: 'claude-sonnet', label: 'Claude Sonnet', provider: 'anthropic', model: 'claude-3-7-sonnet-latest' },\n { id: 'gpt-4o', label: 'GPT-4o', provider: 'openai', model: 'gpt-4o' },\n { id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro', provider: 'google', model: 'gemini-2.5-pro' },\n];\n\n/** Pick decimal precision by magnitude so sub-cent costs stay legible. */\nfunction formatCostUsd(usd: number): string {\n if (usd >= 1) return usd.toFixed(2);\n if (usd >= 0.01) return usd.toFixed(3);\n return usd.toFixed(4);\n}\n\ninterface AIChatPanelAgentProps {\n agent: UseEditorAgentReturn;\n editor: Editor | null;\n}\n\nconst ToolProgressLine: React.FC<{ entry: AgentToolProgress }> = ({ entry }) => {\n const { t } = useI18n();\n if (!entry.label) return null; // hidden tools (e.g. mint_node_id)\n\n if (entry.status === 'running') {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-stone-500 dark:text-stone-400 py-0.5\">\n <Loader2 size={11} className=\"animate-spin\" />\n <span>{entry.label}</span>\n </div>\n );\n }\n if (entry.status === 'done') {\n return (\n <div className=\"flex items-center gap-1.5 text-xs text-stone-400 dark:text-stone-500 py-0.5\">\n <Check size={11} />\n <span>{entry.label}</span>\n </div>\n );\n }\n return (\n <div\n className=\"flex items-center gap-1.5 text-xs text-red-500 py-0.5\"\n title={entry.error ?? t('editor.ai.toolStatus.failed') /* i18n: en-only for v1 */}\n >\n <AlertCircle size={11} />\n <span>{entry.label}</span>\n </div>\n );\n};\n\nconst RecentChangesStrip: React.FC<{ changes: AgentChange[] }> = ({ changes }) => {\n const { t } = useI18n();\n const [expanded, setExpanded] = useState(false);\n const active = changes.filter((c) => !c.revertedAt);\n if (active.length === 0) return null;\n\n return (\n <div className=\"border-b border-stone-200 dark:border-stone-700 bg-stone-50 dark:bg-stone-900/50\">\n <button\n onClick={() => setExpanded((v) => !v)}\n className=\"w-full flex items-center gap-1.5 px-4 py-1.5 text-xs text-stone-600 dark:text-stone-400 hover:bg-stone-100 dark:hover:bg-stone-800\"\n >\n {expanded ? <ChevronDown size={12} /> : <ChevronRight size={12} />}\n <span className=\"font-medium\">\n {t('editor.ai.recentChanges') /* i18n: en-only for v1 */} ({active.length})\n </span>\n </button>\n {expanded && (\n <ul className=\"px-4 pb-2 space-y-0.5 max-h-32 overflow-y-auto\">\n {active.map((c) => (\n <li\n key={c.id}\n className=\"flex items-center justify-between text-[11px] text-stone-500 dark:text-stone-500\"\n >\n <span className=\"font-mono truncate\">{c.tool}</span>\n <span className=\"ml-2 flex-shrink-0\">\n {new Date(c.appliedAt).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nconst ModelPicker: React.FC<{\n model: string;\n setProvider: (p: ProviderName, model: string) => void;\n disabled: boolean;\n}> = ({ model, setProvider, disabled }) => {\n const { t } = useI18n();\n const current = MODEL_OPTIONS.find((m) => m.model === model) ?? MODEL_OPTIONS[0];\n return (\n <select\n value={current.id}\n disabled={disabled}\n onChange={(e) => {\n const next = MODEL_OPTIONS.find((m) => m.id === e.target.value);\n if (next) setProvider(next.provider, next.model);\n }}\n className=\"text-xs bg-transparent border border-stone-200 dark:border-stone-700 rounded px-1.5 py-0.5 text-stone-600 dark:text-stone-300 focus:outline-none focus:ring-1 focus:ring-[#111111] dark:focus:ring-white disabled:opacity-50\"\n title={t('editor.ai.model.label') /* i18n: en-only for v1 */}\n >\n {MODEL_OPTIONS.map((m) => (\n <option key={m.id} value={m.id}>{m.label}</option>\n ))}\n </select>\n );\n};\n\nconst AIChatPanelAgent: React.FC<AIChatPanelAgentProps> = ({ agent }) => {\n const { t } = useI18n();\n const [input, setInput] = useState('');\n const [showHistory, setShowHistory] = useState(false);\n const [clarificationAnswers, setClarificationAnswers] = useState<Record<number, string>>({});\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const historyRef = useRef<HTMLDivElement>(null);\n\n const {\n state,\n messages,\n statusMessage,\n errorMessage,\n streamingMessageId,\n activeChanges,\n model,\n setProvider,\n cumulativeCostUsd,\n closePanel,\n submitPrompt,\n submitClarificationAnswer,\n cancel,\n startNewChat,\n historySessions,\n isHistoryLoading,\n fetchHistory,\n loadSession,\n } = agent;\n\n const isProcessing = state === 'RUNNING' || state === 'INITIALIZING';\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages, state]);\n\n useEffect(() => {\n if (state === 'IDLE') {\n inputRef.current?.focus();\n }\n }, [state]);\n\n useEffect(() => {\n if (!showHistory) return;\n const handleClickOutside = (e: MouseEvent) => {\n if (historyRef.current && !historyRef.current.contains(e.target as Node)) {\n setShowHistory(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [showHistory]);\n\n const toggleHistory = () => {\n const next = !showHistory;\n setShowHistory(next);\n if (next) fetchHistory();\n };\n\n const handleSelectSession = (chatId: string) => {\n setShowHistory(false);\n loadSession(chatId);\n };\n\n const handleSubmit = () => {\n const trimmed = input.trim();\n if (!trimmed || isProcessing || state === 'AWAITING_USER') return;\n setInput('');\n submitPrompt(trimmed);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const inputDisabled = isProcessing || state === 'AWAITING_USER';\n\n return (\n <div className=\"flex flex-col h-full bg-white dark:bg-stone-900 border-l border-stone-200 dark:border-stone-700\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-stone-200 dark:border-stone-700\">\n <div className=\"flex items-center gap-2\">\n <Sparkles size={16} className=\"text-[#111111] dark:text-white\" />\n <span className=\"text-sm font-semibold text-stone-800 dark:text-stone-200\">\n {t('editor.ai.title')}\n </span>\n {cumulativeCostUsd > 0 && (\n <span\n className=\"text-[11px] text-stone-400 dark:text-stone-500 tabular-nums\"\n title=\"Cumulative LLM cost for this chat session\"\n >\n ${formatCostUsd(cumulativeCostUsd)}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-1\">\n <ModelPicker\n model={model}\n setProvider={setProvider}\n disabled={isProcessing}\n />\n <div className=\"relative\" ref={historyRef}>\n <button\n onClick={toggleHistory}\n disabled={isProcessing}\n className=\"p-1 rounded hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={t('editor.ai.history')}\n >\n <History size={16} className=\"text-stone-500\" />\n </button>\n {showHistory && (\n <div className=\"absolute right-0 top-full mt-1 w-64 max-h-72 overflow-y-auto bg-white dark:bg-stone-800 border border-stone-200 dark:border-stone-700 rounded-lg shadow-lg z-50\">\n <div className=\"px-3 py-2 border-b border-stone-200 dark:border-stone-700\">\n <span className=\"text-xs font-semibold text-stone-500 dark:text-stone-400 uppercase tracking-wider\">\n {t('editor.ai.history')}\n </span>\n </div>\n {isHistoryLoading ? (\n <div className=\"flex items-center justify-center py-6\">\n <Loader2 size={16} className=\"animate-spin text-stone-400\" />\n </div>\n ) : historySessions.length === 0 ? (\n <p className=\"text-xs text-stone-400 dark:text-stone-500 text-center py-6\">\n {t('editor.ai.noHistory')}\n </p>\n ) : (\n <div className=\"py-1\">\n {historySessions.map((session) => (\n <button\n key={session.chatId}\n onClick={() => handleSelectSession(session.chatId)}\n className=\"w-full text-left px-3 py-2 hover:bg-stone-50 dark:hover:bg-stone-700 transition-colors\"\n >\n <p className=\"text-sm text-stone-800 dark:text-stone-200 truncate\">\n {session.chatTitle}\n </p>\n <p className=\"text-xs text-stone-400 dark:text-stone-500 mt-0.5\">\n {session.messageCount} {t('editor.ai.historyMessages')} &middot;{' '}\n {new Date(session.lastEdited).toLocaleDateString()}\n </p>\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n <button\n onClick={startNewChat}\n disabled={isProcessing}\n className=\"p-1 rounded hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={t('editor.ai.newChat')}\n >\n <Plus size={16} className=\"text-stone-500\" />\n </button>\n <button\n onClick={closePanel}\n className=\"p-1 rounded hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors\"\n title={t('editor.ai.close')}\n >\n <X size={16} className=\"text-stone-500\" />\n </button>\n </div>\n </div>\n\n {/* Recent AI changes strip */}\n <RecentChangesStrip changes={activeChanges} />\n\n {/* Messages area */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.length === 0 && state !== 'INITIALIZING' && (\n <div className=\"flex flex-col items-center justify-center h-full text-center px-4\">\n <Sparkles size={32} className=\"text-stone-300 dark:text-stone-600 mb-3\" />\n <p className=\"text-sm text-stone-500 dark:text-stone-400 mb-1\">\n {t('editor.ai.emptyState')}\n </p>\n <p className=\"text-xs text-stone-400 dark:text-stone-500\">\n {t('editor.ai.emptyStateHint')}\n </p>\n </div>\n )}\n\n {messages.map((msg: AgentChatMessage) => {\n const isStreaming = msg.id === streamingMessageId;\n // Hide empty streaming placeholder if no content AND no tool progress yet\n if (isStreaming && !msg.content && !(msg.toolProgress && msg.toolProgress.length > 0)) {\n return null;\n }\n\n return (\n <div\n key={msg.id}\n className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}\n >\n <div\n className={`max-w-[85%] rounded-lg px-3 py-2 text-sm ${\n msg.role === 'user'\n ? 'bg-[#111111] text-white'\n : 'bg-stone-100 dark:bg-stone-800 text-stone-800 dark:text-stone-200'\n }`}\n >\n {msg.role === 'assistant' ? (\n <>\n {msg.content && (\n <div className=\"prose prose-sm dark:prose-invert max-w-none prose-p:mb-2 prose-p:leading-relaxed prose-headings:mb-2 prose-headings:mt-3 prose-ul:my-1 prose-ol:my-1 prose-li:my-0\">\n <ReactMarkdown remarkPlugins={mdRemarkPlugins} components={mdComponents}>\n {msg.content}\n </ReactMarkdown>\n {isStreaming && (\n <span className=\"inline-block w-1.5 h-4 bg-stone-400 dark:bg-stone-500 animate-pulse ml-0.5 align-text-bottom rounded-sm\" />\n )}\n </div>\n )}\n {msg.toolProgress && msg.toolProgress.length > 0 && (\n <div className=\"mt-1.5 space-y-0\">\n {msg.toolProgress.map((entry) => (\n <ToolProgressLine key={entry.id} entry={entry} />\n ))}\n </div>\n )}\n {msg.clarificationQuestions &&\n msg.clarificationQuestions.length > 0 &&\n state !== 'AWAITING_USER' && (\n <div className=\"mt-2 flex items-center gap-1.5 text-xs text-stone-400 dark:text-stone-500\">\n <HelpCircle size={12} />\n <span>{t('editor.ai.clarificationAnswered')}</span>\n </div>\n )}\n </>\n ) : (\n <p className=\"whitespace-pre-wrap\">{msg.content}</p>\n )}\n </div>\n </div>\n );\n })}\n\n {/* Clarification form — modeled on AIChatPanel.tsx AWAITING_CLARIFICATION block */}\n {state === 'AWAITING_USER' &&\n (() => {\n const lastMsg = [...messages]\n .reverse()\n .find((m) => m.clarificationQuestions && m.clarificationQuestions.length > 0);\n const questions = lastMsg?.clarificationQuestions ?? [];\n if (questions.length === 0) return null;\n\n const allAnswered = questions.every((_, i) => clarificationAnswers[i]?.trim());\n\n const handleClarificationSubmit = () => {\n if (!allAnswered) return;\n const answers = questions.map((_, i) => clarificationAnswers[i].trim());\n setClarificationAnswers({});\n submitClarificationAnswer(answers);\n };\n\n return (\n <div className=\"rounded-xl border border-amber-200 dark:border-amber-800 bg-gradient-to-b from-amber-50 to-white dark:from-amber-950/30 dark:to-stone-900 overflow-hidden\">\n <div className=\"flex items-center gap-2 px-4 py-3 border-b border-amber-200 dark:border-amber-800 bg-amber-50/80 dark:bg-amber-950/40\">\n <HelpCircle size={15} className=\"text-amber-600 dark:text-amber-400\" />\n <span className=\"text-sm font-semibold text-amber-800 dark:text-amber-200\">\n {t('editor.ai.clarificationNeeded')}\n </span>\n <span className=\"ml-auto text-[10px] font-medium text-amber-500 dark:text-amber-500 uppercase tracking-wider\">\n {questions.length}{' '}\n {questions.length === 1\n ? t('editor.ai.clarificationQuestion')\n : t('editor.ai.clarificationQuestions')}\n </span>\n </div>\n <div className=\"px-4 py-3 space-y-4\">\n {questions.map((question, qi) => (\n <div key={qi}>\n <label className=\"flex items-start gap-2 mb-1.5\">\n <span className=\"flex-shrink-0 w-5 h-5 rounded-full bg-amber-100 dark:bg-amber-900/50 text-amber-700 dark:text-amber-300 text-[11px] font-bold flex items-center justify-center mt-px\">\n {qi + 1}\n </span>\n <span className=\"text-sm text-stone-700 dark:text-stone-300 leading-snug\">\n {question}\n </span>\n </label>\n <div className=\"ml-7\">\n <input\n type=\"text\"\n value={clarificationAnswers[qi] ?? ''}\n onChange={(e) =>\n setClarificationAnswers((prev) => ({\n ...prev,\n [qi]: e.target.value,\n }))\n }\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey && allAnswered) {\n e.preventDefault();\n handleClarificationSubmit();\n }\n }}\n placeholder={t('editor.ai.clarificationInputPlaceholder')}\n autoFocus={qi === 0}\n className=\"w-full rounded-lg border border-stone-200 dark:border-stone-700 bg-white dark:bg-stone-800 px-3 py-2 text-sm text-stone-800 dark:text-stone-200 placeholder:text-stone-400 focus:outline-none focus:ring-1 focus:ring-amber-500 focus:border-amber-400 dark:focus:border-amber-600 transition-colors\"\n />\n </div>\n </div>\n ))}\n </div>\n <div className=\"px-4 py-3 border-t border-amber-100 dark:border-amber-900/50\">\n <button\n onClick={handleClarificationSubmit}\n disabled={!allAnswered}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-[#111111] text-white text-sm font-medium rounded-lg hover:bg-[#222222] disabled:opacity-40 disabled:cursor-not-allowed transition-all\"\n >\n <Send size={14} />\n {t('editor.ai.submitAnswer')}\n </button>\n </div>\n </div>\n );\n })()}\n\n {/* Processing indicator (no streaming text yet) */}\n {isProcessing && (\n <div className=\"flex items-center gap-2 text-sm text-stone-500 dark:text-stone-400\">\n <Loader2 size={14} className=\"animate-spin\" />\n <span>{statusMessage || t('editor.ai.processing')}</span>\n </div>\n )}\n\n {state === 'ERROR' && (\n <div className=\"flex items-start gap-2 p-3 bg-red-50 dark:bg-red-950/20 rounded-lg border border-red-200 dark:border-red-800\">\n <AlertCircle size={16} className=\"text-red-500 flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-red-700 dark:text-red-300\">{errorMessage}</p>\n <button\n onClick={startNewChat}\n className=\"flex items-center gap-1 text-xs text-red-600 dark:text-red-400 mt-1 hover:underline\"\n >\n <RefreshCw size={12} />\n {t('editor.ai.retry')}\n </button>\n </div>\n </div>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/* Footer — hidden during clarification (form is inline) */}\n {state !== 'AWAITING_USER' && (\n <div className=\"p-3 border-t border-stone-200 dark:border-stone-700\">\n <div className=\"flex items-end gap-1.5\">\n <textarea\n ref={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={\n inputDisabled ? t('editor.ai.inputDisabled') : t('editor.ai.inputPlaceholder')\n }\n disabled={inputDisabled}\n rows={1}\n className=\"flex-1 resize-none rounded-lg border border-stone-200 dark:border-stone-700 bg-white dark:bg-stone-800 px-3 py-2 text-sm text-stone-800 dark:text-stone-200 placeholder:text-stone-400 focus:outline-none focus:ring-1 focus:ring-[#111111] dark:focus:ring-white disabled:opacity-50 disabled:cursor-not-allowed\"\n style={{ minHeight: '38px', maxHeight: '120px' }}\n onInput={(e) => {\n const target = e.target as HTMLTextAreaElement;\n target.style.height = 'auto';\n target.style.height = Math.min(target.scrollHeight, 120) + 'px';\n }}\n />\n {isProcessing ? (\n <button\n onClick={cancel}\n className=\"flex-shrink-0 p-2 rounded-lg bg-stone-200 dark:bg-stone-700 hover:bg-stone-300 dark:hover:bg-stone-600 transition-colors\"\n title={t('editor.ai.cancel')}\n >\n <X size={16} className=\"text-stone-600 dark:text-stone-300\" />\n </button>\n ) : (\n <button\n onClick={handleSubmit}\n disabled={!input.trim() || inputDisabled}\n className=\"flex-shrink-0 p-2 rounded-lg bg-[#111111] text-white hover:bg-[#222222] disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n title={t('editor.ai.send')}\n >\n <Send size={16} />\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default AIChatPanelAgent;\n","/**\n * Minimal English-only i18n stub.\n *\n * The library is English-only for v0. This stub exists so existing call sites\n * (`const { t } = useI18n(); t('editor.ai.send')`) keep working. If your host\n * app needs localisation, swap this hook for your own — every component\n * imports from `../i18n`, so a single barrel file change covers it.\n */\n\nconst EN: Record<string, string> = {\n // EditOperationCard\n 'editor.ai.nodeWillBeDeleted': 'Node will be deleted',\n 'editor.ai.applied': 'Applied',\n 'editor.ai.failed': 'Failed',\n 'editor.ai.applySingle': 'Apply',\n 'editor.ai.include': 'Include',\n 'editor.ai.skip': 'Skip',\n\n // AIChatPanelAgent\n 'editor.ai.toolStatus.failed': 'Failed',\n 'editor.ai.recentChanges': 'Recent changes',\n 'editor.ai.model.label': 'Model',\n 'editor.ai.title': 'AI Assistant',\n 'editor.ai.history': 'History',\n 'editor.ai.noHistory': 'No previous chats',\n 'editor.ai.historyMessages': 'messages',\n 'editor.ai.newChat': 'New chat',\n 'editor.ai.close': 'Close',\n 'editor.ai.emptyState': 'Start a conversation to edit your document',\n 'editor.ai.emptyStateHint': 'Ask for edits, summaries, or comments',\n 'editor.ai.clarificationAnswered': 'Answered',\n 'editor.ai.clarificationNeeded': 'Clarification needed',\n 'editor.ai.clarificationQuestion': 'Please answer:',\n 'editor.ai.clarificationQuestions': 'Please answer the following:',\n 'editor.ai.clarificationInputPlaceholder': 'Your answer...',\n 'editor.ai.submitAnswer': 'Submit',\n 'editor.ai.processing': 'Thinking...',\n 'editor.ai.retry': 'Retry',\n 'editor.ai.inputDisabled': 'Open the editor to chat',\n 'editor.ai.inputPlaceholder': 'Ask the AI...',\n 'editor.ai.cancel': 'Cancel',\n 'editor.ai.send': 'Send',\n};\n\nexport function useI18n(): { t: (key: string, vars?: Record<string, string | number>) => string } {\n return {\n t: (key, vars) => {\n let str = EN[key] ?? key;\n if (vars) {\n for (const [k, v] of Object.entries(vars)) {\n str = str.replace(new RegExp(`\\\\{${k}\\\\}`, 'g'), String(v));\n }\n }\n return str;\n },\n };\n}\n","import { Extension, Mark, type RawCommands } from '@tiptap/core';\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n suggestionMode: {\n enableSuggestionMode: () => ReturnType;\n disableSuggestionMode: () => ReturnType;\n acceptAllSuggestions: () => ReturnType;\n rejectAllSuggestions: () => ReturnType;\n acceptSuggestionById: (id: number) => ReturnType;\n rejectSuggestionById: (id: number) => ReturnType;\n };\n }\n}\nimport {\n suggestChanges,\n suggestChangesKey,\n isSuggestChangesEnabled,\n enableSuggestChanges,\n disableSuggestChanges,\n applySuggestions,\n revertSuggestions,\n applySuggestion,\n revertSuggestion,\n withSuggestChanges,\n} from '@blocknote/prosemirror-suggest-changes';\n\n// Re-export the plugin key so other files can import from this module\nexport { suggestChangesKey } from '@blocknote/prosemirror-suggest-changes';\n\n// Tiptap Mark extension for insertion (tracks added text)\nexport const SuggestionInsertMark = Mark.create({\n name: 'insertion',\n\n addAttributes() {\n return {\n id: { default: 0 },\n };\n },\n\n inclusive() {\n return false;\n },\n\n excludes: 'deletion modification insertion',\n\n parseHTML() {\n return [{\n tag: 'ins[data-id]',\n getAttrs(node) {\n const el = node as HTMLElement;\n if (!el.dataset.id) return false;\n return { id: parseInt(el.dataset.id, 10) };\n },\n }];\n },\n\n renderHTML({ HTMLAttributes, mark }) {\n return ['ins', { 'data-id': String(mark.attrs.id), ...HTMLAttributes }, 0];\n },\n});\n\n// Tiptap Mark extension for deletion (tracks removed text)\nexport const SuggestionDeleteMark = Mark.create({\n name: 'deletion',\n\n addAttributes() {\n return {\n id: { default: 0 },\n };\n },\n\n inclusive() {\n return false;\n },\n\n excludes: 'insertion modification deletion',\n\n parseHTML() {\n return [{\n tag: 'del[data-id]',\n getAttrs(node) {\n const el = node as HTMLElement;\n if (!el.dataset.id) return false;\n return { id: parseInt(el.dataset.id, 10) };\n },\n }];\n },\n\n renderHTML({ HTMLAttributes, mark }) {\n return ['del', { 'data-id': String(mark.attrs.id), ...HTMLAttributes }, 0];\n },\n});\n\n// Tiptap Mark extension for modification (tracks attribute changes)\nexport const SuggestionModificationMark = Mark.create({\n name: 'modification',\n\n addAttributes() {\n return {\n id: { default: 0 },\n type: { default: null },\n attrName: { default: null },\n previousValue: { default: null },\n newValue: { default: null },\n };\n },\n\n inclusive() {\n return false;\n },\n\n excludes: 'deletion insertion',\n\n parseHTML() {\n return [\n {\n tag: 'span[data-type=\"modification\"]',\n getAttrs(node) {\n const el = node as HTMLElement;\n if (!el.dataset.id) return false;\n return {\n id: parseInt(el.dataset.id, 10),\n type: el.dataset.modType,\n previousValue: el.dataset.modPrevVal,\n newValue: el.dataset.modNewVal,\n };\n },\n },\n {\n tag: 'div[data-type=\"modification\"]',\n getAttrs(node) {\n const el = node as HTMLElement;\n if (!el.dataset.id) return false;\n return {\n id: parseInt(el.dataset.id, 10),\n type: el.dataset.modType,\n previousValue: el.dataset.modPrevVal,\n };\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes, mark }) {\n return ['span', {\n 'data-type': 'modification',\n 'data-id': String(mark.attrs.id),\n 'data-mod-type': mark.attrs.type,\n 'data-mod-prev-val': JSON.stringify(mark.attrs.previousValue),\n 'data-mod-new-val': JSON.stringify(mark.attrs.newValue),\n ...HTMLAttributes,\n }, 0];\n },\n});\n\n// Backward-compatible marks for loading existing content stored with old library names.\n// These are read-only: new suggestions use `insertion`/`deletion`, but documents saved\n// with the old `prosemirror-suggestion-mode` library have marks named `suggestion_insert`\n// and `suggestion_delete` with different attrs ({username, data} instead of {id}).\n\nexport const LegacySuggestionInsertMark = Mark.create({\n name: 'suggestion_insert',\n\n addAttributes() {\n return {\n username: { default: '' },\n data: { default: null },\n };\n },\n\n inclusive() {\n return true;\n },\n\n excludes: 'suggestion_delete',\n\n parseHTML() {\n return [{ tag: 'span.suggestion-add' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n // Render as <ins> so it gets the same CSS as new marks\n return ['ins', { class: 'legacy-suggestion', ...HTMLAttributes }, 0];\n },\n});\n\nexport const LegacySuggestionDeleteMark = Mark.create({\n name: 'suggestion_delete',\n\n addAttributes() {\n return {\n username: { default: '' },\n data: { default: null },\n };\n },\n\n inclusive() {\n return true;\n },\n\n excludes: 'suggestion_insert',\n\n parseHTML() {\n return [{ tag: 'span.suggestion-delete' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n // Render as <del> so it gets the same CSS as new marks\n return ['del', { class: 'legacy-suggestion', ...HTMLAttributes }, 0];\n },\n});\n\n// Main Tiptap Extension that registers the ProseMirror plugin and commands\nexport interface SuggestionModeOptions {\n enabled: boolean;\n username: string;\n}\n\nexport const SuggestionMode = Extension.create<SuggestionModeOptions>({\n name: 'suggestionMode',\n\n addOptions() {\n return {\n enabled: false,\n username: 'Anonymous',\n };\n },\n\n addProseMirrorPlugins() {\n return [suggestChanges()];\n },\n\n onCreate() {\n // Wrap the editor view's dispatch with withSuggestChanges.\n // This intercepts transactions BEFORE they are applied — deletions\n // are converted to deletion marks instead of actually removing content.\n const view = this.editor.view;\n const wrappedDispatch = withSuggestChanges(view.dispatch.bind(view));\n view.dispatch = wrappedDispatch.bind(view);\n\n // If initially enabled (e.g. for reviewers), turn it on now\n if (this.options.enabled) {\n enableSuggestChanges(this.editor.view.state, this.editor.view.dispatch);\n }\n },\n\n addCommands() {\n return {\n enableSuggestionMode:\n () =>\n ({ view }) => {\n return enableSuggestChanges(view.state, view.dispatch);\n },\n disableSuggestionMode:\n () =>\n ({ view }) => {\n return disableSuggestChanges(view.state, view.dispatch);\n },\n acceptAllSuggestions:\n () =>\n ({ view }) => {\n return applySuggestions(view.state, view.dispatch);\n },\n rejectAllSuggestions:\n () =>\n ({ view }) => {\n return revertSuggestions(view.state, view.dispatch);\n },\n acceptSuggestionById:\n (id: number) =>\n ({ view }) => {\n return applySuggestion(id)(view.state, view.dispatch);\n },\n rejectSuggestionById:\n (id: number) =>\n ({ view }) => {\n return revertSuggestion(id)(view.state, view.dispatch);\n },\n };\n },\n});\n","import { Mark, Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport { suggestChangesKey } from './suggestionMode';\n\nexport type CommentSeverity = 'high' | 'moderate' | 'low';\n\n// Mark that wraps commented text with a commentId attribute\nexport const InlineCommentMark = Mark.create({\n name: 'inlineComment',\n\n addAttributes() {\n return {\n commentId: { default: null },\n resolved: { default: false },\n severity: { default: 'moderate' as CommentSeverity },\n isAI: { default: false },\n };\n },\n\n inclusive() {\n return false;\n },\n\n // Allow multiple inlineComment marks on the same text (overlapping comments)\n excludes: '',\n\n parseHTML() {\n return [{ tag: 'span[data-comment-id]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n const resolved = HTMLAttributes.resolved;\n const severity: CommentSeverity = HTMLAttributes.severity || 'moderate';\n const isAI = HTMLAttributes.isAI;\n const classes = ['comment-highlight', `comment-severity-${severity}`];\n if (resolved) classes.push('resolved');\n if (isAI) classes.push('comment-ai');\n return [\n 'span',\n {\n class: classes.join(' '),\n 'data-comment-id': HTMLAttributes.commentId,\n 'data-comment-resolved': resolved ? 'true' : undefined,\n 'data-comment-severity': severity,\n 'data-comment-ai': isAI ? 'true' : undefined,\n },\n 0,\n ];\n },\n});\n\nexport const inlineCommentPluginKey = new PluginKey('inlineCommentClick');\nexport const pendingHighlightPluginKey = new PluginKey('pendingCommentHighlight');\n\n// Extension that provides commands and click handling for comments\nexport const InlineComments = Extension.create({\n name: 'inlineComments',\n\n addStorage() {\n return {\n activeCommentId: null as string | null,\n };\n },\n\n addCommands() {\n return {\n addCommentMark:\n (commentId: string, severity: CommentSeverity = 'moderate') =>\n ({ chain }: any) => {\n return chain()\n .command(({ tr }: any) => {\n tr.setMeta(suggestChangesKey, { skip: true });\n return true;\n })\n .setMark('inlineComment', { commentId, resolved: false, severity })\n .run();\n },\n removeCommentMark:\n (commentId: string) =>\n ({ tr, state, dispatch }: any) => {\n const { doc } = state;\n let found = false;\n doc.descendants((node: any, pos: number) => {\n if (!node.isText) return;\n const mark = node.marks.find(\n (m: any) => m.type.name === 'inlineComment' && m.attrs.commentId === commentId\n );\n if (mark) {\n tr.removeMark(pos, pos + node.nodeSize, mark);\n found = true;\n }\n });\n if (found && dispatch) {\n tr.setMeta(suggestChangesKey, { skip: true });\n dispatch(tr);\n }\n return found;\n },\n setCommentResolved:\n (commentId: string, resolved: boolean) =>\n ({ tr, state, dispatch }: any) => {\n const { doc } = state;\n const markType = state.schema.marks.inlineComment;\n let found = false;\n doc.descendants((node: any, pos: number) => {\n if (!node.isText) return;\n const mark = node.marks.find(\n (m: any) => m.type.name === 'inlineComment' && m.attrs.commentId === commentId\n );\n if (mark) {\n tr.removeMark(pos, pos + node.nodeSize, mark);\n tr.addMark(pos, pos + node.nodeSize, markType.create({ ...mark.attrs, commentId, resolved }));\n found = true;\n }\n });\n if (found && dispatch) {\n tr.setMeta(suggestChangesKey, { skip: true });\n dispatch(tr);\n }\n return found;\n },\n setCommentSeverity:\n (commentId: string, severity: CommentSeverity) =>\n ({ tr, state, dispatch }: any) => {\n const { doc } = state;\n const markType = state.schema.marks.inlineComment;\n let found = false;\n doc.descendants((node: any, pos: number) => {\n if (!node.isText) return;\n const mark = node.marks.find(\n (m: any) => m.type.name === 'inlineComment' && m.attrs.commentId === commentId\n );\n if (mark) {\n tr.removeMark(pos, pos + node.nodeSize, mark);\n tr.addMark(pos, pos + node.nodeSize, markType.create({ ...mark.attrs, severity }));\n found = true;\n }\n });\n if (found && dispatch) {\n tr.setMeta(suggestChangesKey, { skip: true });\n dispatch(tr);\n }\n return found;\n },\n } as any;\n },\n\n addProseMirrorPlugins() {\n const extension = this;\n return [\n new Plugin({\n key: inlineCommentPluginKey,\n state: {\n init() {\n return DecorationSet.empty;\n },\n apply(tr, oldSet, _oldState, newState) {\n // Rebuild dot decorations from marks in the document\n const decorations: Decoration[] = [];\n const seenIds = new Set<string>();\n\n newState.doc.descendants((node: any, pos: number) => {\n if (!node.isText) return;\n for (const mark of node.marks) {\n if (mark.type.name !== 'inlineComment' || !mark.attrs.commentId) continue;\n const id = mark.attrs.commentId;\n if (seenIds.has(id)) continue;\n if (mark.attrs.resolved) { seenIds.add(id); continue; }\n\n // Find the last position for this comment mark\n let endPos = pos + node.nodeSize;\n // Look ahead for continuation of this mark\n const parent = newState.doc.resolve(pos).parent;\n let scanning = false;\n parent.forEach((child: any, offset: number) => {\n const childPos = newState.doc.resolve(pos).start() + offset;\n if (childPos === pos) { scanning = true; }\n if (!scanning) return;\n if (!child.isText) return;\n const hasMark = child.marks.some(\n (m: any) => m.type.name === 'inlineComment' && m.attrs.commentId === id\n );\n if (hasMark) {\n endPos = childPos + child.nodeSize;\n } else if (scanning && childPos > pos) {\n scanning = false;\n }\n });\n\n seenIds.add(id);\n const severity = mark.attrs.severity || 'moderate';\n const resolved = mark.attrs.resolved;\n const isAI = mark.attrs.isAI;\n\n // Place a widget decoration at the end of the comment range\n decorations.push(\n Decoration.widget(endPos, () => {\n const dot = document.createElement('span');\n dot.className = `comment-dot ${isAI ? 'comment-dot-ai' : `comment-dot-${severity}`}${resolved ? ' comment-dot-resolved' : ''}`;\n dot.setAttribute('data-comment-id', id);\n dot.title = isAI ? 'AI review comment' : 'Go to comment';\n return dot;\n }, { side: 1, key: `comment-dot-${id}` })\n );\n }\n });\n\n return DecorationSet.create(newState.doc, decorations);\n },\n },\n props: {\n decorations(state) {\n return this.getState(state);\n },\n handleClick(view, pos, event) {\n const target = event.target as HTMLElement;\n\n // Click on the comment dot widget\n if (target.classList.contains('comment-dot')) {\n const commentId = target.getAttribute('data-comment-id');\n if (commentId) {\n extension.storage.activeCommentId = commentId;\n view.dispatch(\n view.state.tr.setMeta(inlineCommentPluginKey, { commentId, source: 'dot' })\n );\n return true;\n }\n }\n\n // Click on highlighted comment text\n const highlight = target.closest('.comment-highlight') as HTMLElement | null;\n if (highlight) {\n const commentId = highlight.getAttribute('data-comment-id');\n if (commentId) {\n extension.storage.activeCommentId = commentId;\n view.dispatch(\n view.state.tr.setMeta(inlineCommentPluginKey, { commentId, source: 'highlight' })\n );\n return false; // don't consume — allow cursor placement\n }\n }\n\n // Also check marks at the clicked position\n const resolved = view.state.doc.resolve(pos);\n const marks = resolved.marks();\n for (const mark of marks) {\n if (mark.type.name === 'inlineComment' && mark.attrs.commentId) {\n const commentId = mark.attrs.commentId;\n extension.storage.activeCommentId = commentId;\n view.dispatch(\n view.state.tr.setMeta(inlineCommentPluginKey, { commentId, source: 'highlight' })\n );\n return false;\n }\n }\n\n return false;\n },\n },\n }),\n // Pending comment highlight — a temporary decoration shown while the user is writing a comment\n new Plugin({\n key: pendingHighlightPluginKey,\n state: {\n init() {\n return DecorationSet.empty;\n },\n apply(tr, oldSet, _oldState, newState) {\n const meta = tr.getMeta(pendingHighlightPluginKey);\n if (meta === null) {\n // Explicitly cleared\n return DecorationSet.empty;\n }\n if (meta && typeof meta === 'object' && 'from' in meta && 'to' in meta) {\n const { from, to } = meta as { from: number; to: number };\n const deco = Decoration.inline(from, to, {\n class: 'comment-pending-highlight',\n });\n return DecorationSet.create(newState.doc, [deco]);\n }\n // Map through document changes so the highlight stays in sync with edits\n return oldSet.map(tr.mapping, tr.doc);\n },\n },\n props: {\n decorations(state) {\n return this.getState(state);\n },\n },\n }),\n ];\n },\n});\n","import { Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport { Slice, Fragment } from '@tiptap/pm/model';\nimport {\n NODE_ID_ATTR,\n NODE_ID_HTML_ATTR,\n ID_NODE_TYPES,\n generateUniqueNodeId,\n collectAllSynkIds,\n} from '../utils/nodeIdUtils';\n\nexport interface NodeIdOptions {\n types: string[];\n}\n\nexport const nodeIdPluginKey = new PluginKey('nodeId');\n\n/**\n * Strip synkId attributes from all nodes in a fragment (recursive).\n * Returns a new fragment with all synkIds set to null.\n */\nfunction stripIdsFromFragment(fragment: Fragment): Fragment {\n const nodes: ProseMirrorNode[] = [];\n\n for (let i = 0; i < fragment.childCount; i++) {\n const child = fragment.child(i);\n const strippedContent = stripIdsFromFragment(child.content);\n\n if (child.attrs[NODE_ID_ATTR] !== undefined) {\n nodes.push(\n child.type.create(\n { ...child.attrs, [NODE_ID_ATTR]: null },\n strippedContent,\n child.marks\n )\n );\n } else {\n if (strippedContent === child.content) {\n nodes.push(child);\n } else {\n nodes.push(child.copy(strippedContent));\n }\n }\n }\n\n return Fragment.from(nodes);\n}\n\nfunction fragmentNeedsNodeIds(fragment: Fragment, types: string[]): boolean {\n let needsIds = false;\n\n fragment.descendants((node) => {\n if (!types.includes(node.type.name)) return true;\n if (!node.attrs[NODE_ID_ATTR]) {\n needsIds = true;\n return false;\n }\n return true;\n });\n\n return needsIds;\n}\n\nfunction transactionMayRequireNodeIdAssignment(\n transaction: { steps: Array<{ slice?: Slice }> },\n types: string[]\n): boolean {\n for (const step of transaction.steps) {\n if (!('slice' in step) || !step.slice) continue;\n if (step.slice.size === 0) continue;\n if (fragmentNeedsNodeIds(step.slice.content, types)) {\n return true;\n }\n }\n return false;\n}\n\nexport const NodeId = Extension.create<NodeIdOptions>({\n name: 'nodeId',\n\n addOptions() {\n return {\n types: ID_NODE_TYPES,\n };\n },\n\n /**\n * Assign synkIds to all nodes in the initial document on editor creation.\n * appendTransaction only runs on docChanged, so TipTap's default empty\n * paragraph (or any pre-loaded content set before the first user edit)\n * would never receive synkIds without this.\n *\n * onCreate fires after the editor is fully constructed but before React\n * effects, so section detection and serialization will always see IDs.\n */\n onCreate() {\n const { editor } = this;\n const { types } = this.options;\n const { doc } = editor.state;\n const existingIds = collectAllSynkIds(doc);\n const tr = editor.state.tr;\n let modified = false;\n\n doc.descendants((node, pos) => {\n if (types.includes(node.type.name) && !node.attrs[NODE_ID_ATTR]) {\n const newId = generateUniqueNodeId(node.type.name, existingIds);\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [NODE_ID_ATTR]: newId,\n });\n modified = true;\n }\n });\n\n if (modified) {\n editor.view.dispatch(tr);\n }\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n [NODE_ID_ATTR]: {\n default: null,\n parseHTML: (element: HTMLElement) =>\n element.getAttribute(NODE_ID_HTML_ATTR) || null,\n renderHTML: (attributes: Record<string, unknown>) => {\n if (!attributes[NODE_ID_ATTR]) return {};\n return { [NODE_ID_HTML_ATTR]: attributes[NODE_ID_ATTR] };\n },\n },\n },\n },\n ];\n },\n\n addProseMirrorPlugins() {\n const { types } = this.options;\n\n return [\n new Plugin({\n key: nodeIdPluginKey,\n\n appendTransaction(transactions, _oldState, newState) {\n // Only process if there were actual document changes\n const docChanged = transactions.some((tr) => tr.docChanged);\n if (!docChanged) return null;\n\n // Fast-path: for plain text edits, skip expensive full-document ID scan.\n // Most typing transactions don't introduce new ID-bearing nodes.\n const mightNeedIds = transactions.some((tr) =>\n transactionMayRequireNodeIdAssignment(\n tr as { steps: Array<{ slice?: Slice }> },\n types\n )\n );\n if (!mightNeedIds) {\n return null;\n }\n\n const { doc, tr } = newState;\n const existingIds = collectAllSynkIds(doc);\n let modified = false;\n\n doc.descendants((node, pos) => {\n if (\n types.includes(node.type.name) &&\n !node.attrs[NODE_ID_ATTR]\n ) {\n const newId = generateUniqueNodeId(node.type.name, existingIds);\n tr.setNodeMarkup(pos, undefined, {\n ...node.attrs,\n [NODE_ID_ATTR]: newId,\n });\n modified = true;\n }\n });\n\n return modified ? tr : null;\n },\n\n props: {\n transformPasted(slice) {\n const strippedContent = stripIdsFromFragment(slice.content);\n return new Slice(\n strippedContent,\n slice.openStart,\n slice.openEnd\n );\n },\n },\n }),\n ];\n },\n});\n","import { customAlphabet } from 'nanoid';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\n\nexport const NODE_ID_ATTR = 'synkId';\nexport const NODE_ID_HTML_ATTR = 'data-synk-id';\n\nconst ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';\nconst ID_LENGTH = 4;\nconst nanoid = customAlphabet(ALPHABET, ID_LENGTH);\n\n/** Maps ProseMirror node type names to their ID prefix */\nconst PREFIX_MAP: Record<string, string> = {\n paragraph: 'p',\n heading: 'p',\n listItem: 'p',\n table: 't',\n tableCell: 'c',\n tableHeader: 'c',\n};\n\n/** All node type names that should receive synkId attributes */\nexport const ID_NODE_TYPES = Object.keys(PREFIX_MAP);\n\n/**\n * Generate a prefixed node ID for the given node type.\n * E.g., paragraph → \"p:7a3f\", table → \"t:8x2a\", tableCell → \"c:3f7b\"\n */\nexport function generateNodeId(nodeTypeName: string): string {\n const prefix = PREFIX_MAP[nodeTypeName];\n if (!prefix) {\n throw new Error(`No ID prefix defined for node type: ${nodeTypeName}`);\n }\n return `${prefix}:${nanoid()}`;\n}\n\n/**\n * Find the first node in the document with the given synkId.\n * Returns the node and its position, or null if not found.\n */\nexport function findNodeBySynkId(\n doc: ProseMirrorNode,\n synkId: string\n): { node: ProseMirrorNode; pos: number } | null {\n let result: { node: ProseMirrorNode; pos: number } | null = null;\n\n doc.descendants((node, pos) => {\n if (result) return false; // stop traversal once found\n if (node.attrs[NODE_ID_ATTR] === synkId) {\n result = { node, pos };\n return false;\n }\n });\n\n return result;\n}\n\n/**\n * Collect all existing synkIds in the document into a Set.\n * Used for collision detection when assigning new IDs.\n */\nexport function collectAllSynkIds(doc: ProseMirrorNode): Set<string> {\n const ids = new Set<string>();\n\n doc.descendants((node) => {\n const id = node.attrs[NODE_ID_ATTR];\n if (id) {\n ids.add(id);\n }\n });\n\n return ids;\n}\n\n/**\n * Resolve a ProseMirror position to the nearest ancestor node's synkId.\n * Walks up the depth chain to find the closest node with a synkId attribute.\n */\nexport function resolvePositionToSynkId(\n doc: ProseMirrorNode,\n pos: number\n): string | null {\n try {\n const resolved = doc.resolve(pos);\n for (let depth = resolved.depth; depth > 0; depth--) {\n const node = resolved.node(depth);\n const id = node.attrs[NODE_ID_ATTR];\n if (id) return id;\n }\n } catch {\n // Position may be out of range\n }\n return null;\n}\n\n/**\n * Generate a unique node ID that doesn't collide with any existing ID in the document.\n */\nexport function generateUniqueNodeId(\n nodeTypeName: string,\n existingIds: Set<string>\n): string {\n let id = generateNodeId(nodeTypeName);\n // Extremely unlikely with 36^4 (~1.68M) combinations, but safe\n while (existingIds.has(id)) {\n id = generateNodeId(nodeTypeName);\n }\n existingIds.add(id);\n return id;\n}\n","import { Extension } from '@tiptap/core';\n\n// Adds a `sectionId` attribute to block nodes (paragraph, heading, listItem)\n// that round-trips to a `data-section=\"...\"` attribute on the rendered HTML.\n// Used by CLM (clause anchors / jump-to-section) and harmless when nodes\n// don't carry a sectionId. Independent of NodeId — NodeId mints synthetic\n// IDs for AI ops; SectionId preserves business identifiers from the BE.\nexport const SectionId = Extension.create({\n name: 'sectionId',\n\n addGlobalAttributes() {\n return [\n {\n types: ['paragraph', 'heading', 'listItem'],\n attributes: {\n sectionId: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-section'),\n renderHTML: (attrs) =>\n attrs.sectionId ? { 'data-section': attrs.sectionId as string } : {},\n },\n },\n },\n ];\n },\n});\n","import { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { Editor } from '@tiptap/react';\nimport { suggestChangesKey, isSuggestChangesEnabled } from '@blocknote/prosemirror-suggest-changes';\nimport type { Suggestion, SuggestionType, TrackChangesState } from '../types';\n\nconst AI_USERNAME = 'AI';\n\nfunction extractSuggestions(editor: Editor): Suggestion[] {\n const { doc } = editor.state;\n const suggestions: Suggestion[] = [];\n\n doc.descendants((node, pos) => {\n if (!node.isText) return;\n\n // Check new library marks\n const insertMark = node.marks.find((m) => m.type.name === 'insertion');\n const deleteMark = node.marks.find((m) => m.type.name === 'deletion');\n // Check legacy marks from old library\n const legacyInsertMark = node.marks.find((m) => m.type.name === 'suggestion_insert');\n const legacyDeleteMark = node.marks.find((m) => m.type.name === 'suggestion_delete');\n\n const isInsert = insertMark || legacyInsertMark;\n const isDelete = deleteMark || legacyDeleteMark;\n const mark = isInsert || isDelete;\n if (!mark) return;\n\n const type: SuggestionType = isInsert ? 'insertion' : 'deletion';\n const suggestionId: number = mark.attrs.id ?? 0;\n const username: string = mark.attrs.username || 'User';\n const from = pos;\n const to = pos + node.nodeSize;\n\n suggestions.push({\n id: `${type}-${suggestionId}-${from}-${to}`,\n type,\n author: {\n username,\n isAI: username === AI_USERNAME,\n },\n text: node.text || '',\n from,\n to,\n data: { suggestionId, ...mark.attrs.data },\n });\n });\n\n return suggestions;\n}\n\n// Group adjacent suggestions of the same type and suggestion ID\nfunction groupSuggestions(suggestions: Suggestion[]): Suggestion[] {\n if (suggestions.length === 0) return [];\n\n const grouped: Suggestion[] = [];\n let current = { ...suggestions[0] };\n\n for (let i = 1; i < suggestions.length; i++) {\n const next = suggestions[i];\n if (\n next.type === current.type &&\n next.data?.suggestionId === current.data?.suggestionId &&\n next.from === current.to\n ) {\n // Merge adjacent with same suggestion ID\n current = {\n ...current,\n to: next.to,\n text: current.text + next.text,\n id: `${current.type}-${current.data?.suggestionId}-${current.from}-${next.to}`,\n };\n } else {\n grouped.push(current);\n current = { ...next };\n }\n }\n grouped.push(current);\n return grouped;\n}\n\nexport function useTrackChanges(editor: Editor | null) {\n const [enabled, setEnabled] = useState(false);\n const [showPanel, setShowPanel] = useState(false);\n const [rawSuggestions, setRawSuggestions] = useState<Suggestion[]>([]);\n const scheduledExtractRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Extract suggestions with coalescing (avoid full-doc scans for every transaction).\n useEffect(() => {\n if (!editor) return;\n\n const runExtraction = () => {\n const next = extractSuggestions(editor);\n\n setRawSuggestions((prev) => {\n if (prev.length !== next.length) return next;\n for (let i = 0; i < prev.length; i++) {\n if (prev[i].from !== next[i].from || prev[i].to !== next[i].to || prev[i].text !== next[i].text || prev[i].type !== next[i].type) {\n return next;\n }\n }\n return prev; // no change, skip re-render\n });\n };\n\n const scheduleExtraction = () => {\n if (scheduledExtractRef.current) return;\n scheduledExtractRef.current = setTimeout(() => {\n scheduledExtractRef.current = null;\n runExtraction();\n }, 80);\n };\n\n // Initial extraction\n runExtraction();\n\n editor.on('transaction', scheduleExtraction);\n return () => {\n editor.off('transaction', scheduleExtraction);\n if (scheduledExtractRef.current) {\n clearTimeout(scheduledExtractRef.current);\n scheduledExtractRef.current = null;\n }\n };\n }, [editor]);\n\n // Sync enabled state from plugin state\n useEffect(() => {\n if (!editor) return;\n\n const syncState = () => {\n const isEnabled = isSuggestChangesEnabled(editor.state);\n setEnabled((prev) => (prev === isEnabled ? prev : isEnabled));\n };\n\n syncState();\n editor.on('transaction', syncState);\n return () => {\n editor.off('transaction', syncState);\n };\n }, [editor]);\n\n const suggestions = useMemo(() => groupSuggestions(rawSuggestions), [rawSuggestions]);\n\n const toggleSuggestionMode = useCallback(() => {\n if (!editor) return;\n if (enabled) {\n editor.commands.disableSuggestionMode();\n } else {\n editor.commands.enableSuggestionMode();\n }\n }, [editor, enabled]);\n\n const acceptSuggestion = useCallback(\n (suggestion: Suggestion) => {\n if (!editor) return;\n const suggestionId = suggestion.data?.suggestionId as number | undefined;\n if (suggestionId != null) {\n editor.commands.acceptSuggestionById(suggestionId);\n }\n },\n [editor]\n );\n\n const rejectSuggestion = useCallback(\n (suggestion: Suggestion) => {\n if (!editor) return;\n const suggestionId = suggestion.data?.suggestionId as number | undefined;\n if (suggestionId != null) {\n editor.commands.rejectSuggestionById(suggestionId);\n }\n },\n [editor]\n );\n\n const acceptAll = useCallback(() => {\n if (!editor) return;\n editor.commands.acceptAllSuggestions();\n }, [editor]);\n\n const rejectAll = useCallback(() => {\n if (!editor) return;\n editor.commands.rejectAllSuggestions();\n }, [editor]);\n\n const trackChanges: TrackChangesState & {\n toggleSuggestionMode: () => void;\n acceptSuggestion: (s: Suggestion) => void;\n rejectSuggestion: (s: Suggestion) => void;\n acceptAll: () => void;\n rejectAll: () => void;\n setShowPanel: (show: boolean) => void;\n } = useMemo(\n () => ({\n enabled,\n suggestions,\n showPanel,\n suggestionCount: suggestions.length,\n toggleSuggestionMode,\n acceptSuggestion,\n rejectSuggestion,\n acceptAll,\n rejectAll,\n setShowPanel,\n }),\n [enabled, suggestions, showPanel, toggleSuggestionMode, acceptSuggestion, rejectSuggestion, acceptAll, rejectAll]\n );\n\n return trackChanges;\n}\n\nexport type UseTrackChangesReturn = ReturnType<typeof useTrackChanges>;\n","import { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { Editor } from '@tiptap/react';\nimport { inlineCommentPluginKey, pendingHighlightPluginKey } from '../extensions/inlineComment';\nimport { suggestChangesKey } from '../extensions/suggestionMode';\nimport type { Comment, CommentReply, CommentSeverity } from '../types';\n\nfunction extractCommentPositions(editor: Editor): Record<string, { from: number; to: number }> {\n const { doc } = editor.state;\n const posMap: Record<string, { from: number; to: number }> = {};\n\n doc.descendants((node, pos) => {\n if (!node.isText) return;\n // A text node can carry multiple inlineComment marks (overlapping comments)\n const commentMarks = node.marks.filter((m) => m.type.name === 'inlineComment' && m.attrs.commentId);\n\n for (const mark of commentMarks) {\n const id = mark.attrs.commentId;\n const from = pos;\n const to = pos + node.nodeSize;\n\n if (posMap[id]) {\n posMap[id] = {\n from: Math.min(posMap[id].from, from),\n to: Math.max(posMap[id].to, to),\n };\n } else {\n posMap[id] = { from, to };\n }\n }\n });\n\n return posMap;\n}\n\nexport function useComments(editor: Editor | null, draftId: string, username: string, initialComments: Comment[] = []) {\n const [comments, setComments] = useState<Comment[]>(initialComments);\n const [showPanel, setShowPanel] = useState(false);\n const [activeCommentId, setActiveCommentId] = useState<string | null>(null);\n const [pendingSelectionText, setPendingSelectionText] = useState<string | null>(null);\n\n // Store the pending selection so it survives focus loss when the composer textarea steals focus\n const pendingSelectionRef = useRef<{ from: number; to: number; text: string } | null>(null);\n\n // Load comments from localStorage on mount, or use initialComments\n useEffect(() => {\n if (!draftId) return;\n try {\n const stored = localStorage.getItem(`comments-${draftId}`);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (parsed.length > 0) {\n setComments(parsed);\n return;\n }\n }\n\n // If we made it here, there were no stored comments. Use initialComments if available\n if (initialComments.length > 0) {\n setComments(initialComments);\n localStorage.setItem(`comments-${draftId}`, JSON.stringify(initialComments));\n }\n } catch {\n // ignore parse errors\n }\n }, [draftId]);\n\n // Persist comments to localStorage on change\n useEffect(() => {\n if (!draftId) return;\n if (comments.length > 0) {\n localStorage.setItem(`comments-${draftId}`, JSON.stringify(comments));\n } else if (localStorage.getItem(`comments-${draftId}`)) {\n localStorage.removeItem(`comments-${draftId}`);\n }\n }, [comments, draftId]);\n\n // Sync comment positions from ProseMirror marks (debounced to avoid\n // expensive full-doc scans on every keystroke).\n const positionTimerRef = useRef<NodeJS.Timeout | null>(null);\n useEffect(() => {\n if (!editor) return;\n\n const updatePositions = () => {\n const posMap = extractCommentPositions(editor);\n setComments((prev) => {\n // Keep all comments that still have marks in the doc OR are resolved\n const updated = prev\n .filter((c) => c.resolved || posMap[c.id])\n .map((c) =>\n posMap[c.id]\n ? { ...c, from: posMap[c.id].from, to: posMap[c.id].to }\n : c\n );\n const changed = updated.length !== prev.length || updated.some((c, i) => c.from !== prev[i]?.from || c.to !== prev[i]?.to);\n return changed ? updated : prev;\n });\n };\n\n const debouncedUpdate = () => {\n if (positionTimerRef.current) clearTimeout(positionTimerRef.current);\n positionTimerRef.current = setTimeout(updatePositions, 300);\n };\n\n editor.on('transaction', debouncedUpdate);\n return () => {\n editor.off('transaction', debouncedUpdate);\n if (positionTimerRef.current) clearTimeout(positionTimerRef.current);\n };\n }, [editor]);\n\n // Track the last clicked comment info for the inline popover\n const [clickedCommentInfo, setClickedCommentInfo] = useState<{\n commentId: string;\n source: 'dot' | 'highlight';\n } | null>(null);\n\n // Listen for comment clicks from ProseMirror plugin — all clicks route\n // to the inline popover (no right panel auto-open for comments)\n useEffect(() => {\n if (!editor) return;\n\n const handleTransaction = ({ transaction }: any) => {\n const meta = transaction.getMeta(inlineCommentPluginKey);\n if (meta) {\n if (typeof meta === 'object' && meta.commentId) {\n setActiveCommentId(meta.commentId);\n setClickedCommentInfo({ commentId: meta.commentId, source: meta.source });\n } else if (typeof meta === 'string') {\n // Legacy format\n setActiveCommentId(meta);\n setClickedCommentInfo({ commentId: meta, source: 'highlight' });\n }\n }\n };\n\n editor.on('transaction', handleTransaction);\n return () => {\n editor.off('transaction', handleTransaction);\n };\n }, [editor]);\n\n // Apply a temporary decoration highlight on the pending selection range\n const applyPendingHighlight = useCallback((from: number, to: number) => {\n if (!editor) return;\n editor.view.dispatch(\n editor.state.tr.setMeta(pendingHighlightPluginKey, { from, to })\n );\n }, [editor]);\n\n // Remove the temporary decoration highlight\n const clearPendingHighlight = useCallback(() => {\n if (!editor) return;\n editor.view.dispatch(\n editor.state.tr.setMeta(pendingHighlightPluginKey, null)\n );\n pendingSelectionRef.current = null;\n setPendingSelectionText(null);\n }, [editor]);\n\n // Capture the current editor selection so the composer can use it even after focus moves to the textarea\n const captureSelection = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n if (from === to) {\n clearPendingHighlight();\n return;\n }\n const text = editor.state.doc.textBetween(from, to);\n pendingSelectionRef.current = { from, to, text };\n setPendingSelectionText(text);\n applyPendingHighlight(from, to);\n }, [editor, clearPendingHighlight, applyPendingHighlight]);\n\n // Track selection changes to keep pendingSelectionRef fresh\n useEffect(() => {\n if (!editor) return;\n const onSelectionUpdate = () => {\n const { from, to } = editor.state.selection;\n if (from !== to) {\n const text = editor.state.doc.textBetween(from, to);\n pendingSelectionRef.current = { from, to, text };\n setPendingSelectionText(text);\n }\n };\n editor.on('selectionUpdate', onSelectionUpdate);\n return () => { editor.off('selectionUpdate', onSelectionUpdate); };\n }, [editor]);\n\n const addComment = useCallback(\n (text: string, severity: CommentSeverity = 'moderate') => {\n if (!editor) return;\n\n // Use the stored pending selection (survives focus loss to textarea)\n const sel = pendingSelectionRef.current;\n if (!sel) return;\n const { from, to, text: selectedText } = sel;\n\n const id = crypto.randomUUID();\n\n editor\n .chain()\n .setTextSelection({ from, to })\n .command(({ tr }) => {\n tr.setMeta(suggestChangesKey, { skip: true });\n return true;\n })\n .setMark('inlineComment', { commentId: id, severity })\n .run();\n\n const newComment: Comment = {\n id,\n author: { username, isAI: false },\n text,\n replies: [],\n resolved: false,\n severity,\n createdAt: new Date().toISOString(),\n from,\n to,\n selectedText,\n };\n\n setComments((prev) => [...prev, newComment]);\n setActiveCommentId(id);\n // Clear the pending highlight — the real comment mark now takes over\n clearPendingHighlight();\n },\n [editor, username]\n );\n\n const deleteComment = useCallback(\n (commentId: string) => {\n if (!editor) return;\n (editor.commands as any).removeCommentMark(commentId);\n setComments((prev) => prev.filter((c) => c.id !== commentId));\n if (activeCommentId === commentId) setActiveCommentId(null);\n },\n [editor, activeCommentId]\n );\n\n const resolveComment = useCallback((commentId: string) => {\n if (editor) {\n (editor.commands as any).setCommentResolved(commentId, true);\n }\n setComments((prev) =>\n prev.map((c) => (c.id === commentId ? { ...c, resolved: true } : c))\n );\n }, [editor]);\n\n const unresolveComment = useCallback((commentId: string) => {\n if (editor) {\n (editor.commands as any).setCommentResolved(commentId, false);\n }\n setComments((prev) =>\n prev.map((c) => (c.id === commentId ? { ...c, resolved: false } : c))\n );\n }, [editor]);\n\n const setSeverity = useCallback((commentId: string, severity: CommentSeverity) => {\n if (editor) {\n (editor.commands as any).setCommentSeverity(commentId, severity);\n }\n setComments((prev) =>\n prev.map((c) => (c.id === commentId ? { ...c, severity } : c))\n );\n }, [editor]);\n\n const addReply = useCallback(\n (commentId: string, text: string) => {\n const reply: CommentReply = {\n id: crypto.randomUUID(),\n author: { username, isAI: false },\n text,\n createdAt: new Date().toISOString(),\n };\n setComments((prev) =>\n prev.map((c) =>\n c.id === commentId ? { ...c, replies: [...c.replies, reply] } : c\n )\n );\n },\n [username]\n );\n\n const deleteReply = useCallback((commentId: string, replyId: string) => {\n setComments((prev) =>\n prev.map((c) =>\n c.id === commentId\n ? { ...c, replies: c.replies.filter((r) => r.id !== replyId) }\n : c\n )\n );\n }, []);\n\n const resolveAll = useCallback(() => {\n if (editor) {\n comments.forEach((c) => {\n if (!c.resolved) {\n (editor.commands as any).setCommentResolved(c.id, true);\n }\n });\n }\n setComments((prev) => prev.map((c) => ({ ...c, resolved: true })));\n }, [editor, comments]);\n\n /** Merge externally-created comments (e.g. AI reasoning) into state. */\n const addBatchComments = useCallback((newComments: Comment[]) => {\n setComments((prev) => [...prev, ...newComments]);\n }, []);\n\n /** Mark multiple comments as resolved by their IDs. */\n const resolveCommentsByIds = useCallback((ids: string[]) => {\n if (ids.length === 0) return;\n const idSet = new Set(ids);\n if (editor) {\n ids.forEach((id) => (editor.commands as any).setCommentResolved(id, true));\n }\n setComments((prev) =>\n prev.map((c) => (idSet.has(c.id) ? { ...c, resolved: true } : c))\n );\n }, [editor]);\n\n const commentsReturn = useMemo(\n () => ({\n comments,\n showPanel,\n commentCount: comments.length,\n activeCommentId,\n pendingSelectionText,\n clickedCommentInfo,\n setActiveCommentId,\n setShowPanel,\n setClickedCommentInfo,\n captureSelection,\n clearPendingHighlight,\n addComment,\n addBatchComments,\n deleteComment,\n resolveComment,\n resolveCommentsByIds,\n unresolveComment,\n setSeverity,\n addReply,\n deleteReply,\n resolveAll,\n }),\n [\n comments,\n showPanel,\n activeCommentId,\n pendingSelectionText,\n clickedCommentInfo,\n captureSelection,\n clearPendingHighlight,\n addComment,\n addBatchComments,\n deleteComment,\n resolveComment,\n resolveCommentsByIds,\n unresolveComment,\n setSeverity,\n addReply,\n deleteReply,\n resolveAll,\n ]\n );\n\n return commentsReturn;\n}\n\nexport type UseCommentsReturn = ReturnType<typeof useComments>;\n","/**\n * Phase 2a — Agent-loop hook for the rewritten AI editor (spec §11).\n *\n * Owns: state machine, message projection from the Vercel AI SDK `fullStream`,\n * provider/model selection, journal lifetime, chat history persistence.\n *\n * Phase 1's `runAgent` drives the loop; this hook reduces stream parts into UI\n * state and persists transcripts after each turn.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { ModelMessage } from 'ai';\n\nimport { runAgent, type AgentStreamPart } from '../agent/runAgent';\nimport { AgentJournal } from '../agent/journal';\nimport type {\n AgentChange,\n AgentPlaybook,\n AgentComplianceAct,\n} from '../agent/types';\nimport {\n createChatSession,\n getSessionList,\n getChatMessages,\n fetchTurnCost,\n type ChatSession,\n} from '../services/editorApi';\nimport type { Comment, Suggestion } from '../types';\nimport {\n useTiptapOfficeConfig,\n buildFetchInit,\n type ProviderName,\n} from '../config/TiptapOfficeProvider';\n\n// --- Public types (Phase 2b consumes these) -------------------------------\n\nexport type AgentUIState =\n | 'IDLE'\n | 'INITIALIZING'\n | 'RUNNING'\n | 'AWAITING_USER'\n | 'ERROR';\n\nexport type AgentToolProgressStatus = 'running' | 'done' | 'failed';\n\nexport interface AgentToolProgress {\n id: string;\n tool: string;\n label: string;\n status: AgentToolProgressStatus;\n error?: string;\n}\n\nexport interface AgentChatMessage {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n timestamp: number;\n toolProgress?: AgentToolProgress[];\n clarificationQuestions?: string[];\n}\n\nexport interface UseEditorAgentReturn {\n state: AgentUIState;\n messages: AgentChatMessage[];\n statusMessage: string;\n errorMessage: string;\n isPanelOpen: boolean;\n streamingMessageId: string | null;\n\n activeChanges: AgentChange[];\n\n provider: ProviderName;\n model: string;\n setProvider: (p: ProviderName, model: string) => void;\n\n /** USD cost of the most recently completed turn. `null` until the first turn finishes or if pricing lookup failed. */\n lastTurnCostUsd: number | null;\n /** Sum of all per-turn costs since the chat was opened or reset. */\n cumulativeCostUsd: number;\n\n openPanel: () => void;\n closePanel: () => void;\n submitPrompt: (prompt: string, opts?: { playbook?: AgentPlaybook }) => void;\n submitClarificationAnswer: (answers: string[]) => void;\n cancel: () => void;\n startNewChat: () => void;\n\n historySessions: ChatSession[];\n isHistoryLoading: boolean;\n fetchHistory: () => void;\n loadSession: (chatId: string) => void;\n}\n\n// --- Internals ------------------------------------------------------------\n\nlet messageIdCounter = 0;\nfunction nextMessageId(): string {\n return `agent-msg-${++messageIdCounter}-${Date.now()}`;\n}\n\n// --- Label table (spec §12) -----------------------------------------------\n\ninterface SectionInfo {\n id: string;\n title: string;\n}\n\nfunction labelForTool(\n toolName: string,\n input: unknown,\n sectionCache: Map<string, string>\n): string {\n const args = (input ?? {}) as Record<string, unknown>;\n switch (toolName) {\n case 'list_sections':\n return 'Surveying document structure';\n case 'read_section': {\n const sid = typeof args.section_id === 'string' ? args.section_id : '';\n const title = sectionCache.get(sid);\n return title ? `Reading \"${title}\"` : 'Reading section';\n }\n case 'read_document_styles':\n return 'Reading document styles';\n case 'mint_node_id':\n return '';\n case 'replace_text': {\n const target = typeof args.target === 'string' ? args.target : '';\n return target ? `Editing ${target}` : 'Editing paragraph';\n }\n case 'replace_paragraph':\n return 'Rewriting paragraph';\n case 'insert_after':\n case 'insert_before':\n return 'Inserting new content';\n case 'delete_node':\n return 'Removing paragraph';\n case 'add_comment':\n return 'Flagging content';\n case 'replace_cell':\n case 'insert_row':\n case 'delete_row':\n case 'insert_column':\n case 'delete_column':\n return 'Editing table';\n case 'insert_table':\n return 'Inserting table';\n case 'replace_table':\n return 'Replacing table';\n case 'list_my_changes':\n return 'Reviewing prior changes';\n case 'revert_change':\n return 'Reverting prior change';\n case 'ask_user':\n return 'Awaiting your answer';\n case 'lookup_playbook':\n return 'Looking up playbook';\n case 'lookup_compliance_act':\n return 'Looking up regulation';\n default:\n return '';\n }\n}\n\n/** Tool-result `{ ok: false }` detection — Phase 1's edit tools return this shape. */\nfunction isFailedToolResult(output: unknown): boolean {\n return (\n typeof output === 'object' &&\n output !== null &&\n 'ok' in output &&\n (output as { ok: unknown }).ok === false\n );\n}\n\nexport function useEditorAgent(\n editor: Editor | null,\n documentId: string,\n options?: {\n onAICommentsCreated?: (comments: Comment[]) => void;\n comments?: Comment[];\n suggestions?: Suggestion[];\n onCommentsResolved?: (commentIds: string[]) => void;\n /** Optional callback the agent can use to fetch a playbook by id mid-turn\n * (exposed via the `lookup_playbook` tool). */\n loadPlaybook?: (playbookId: string) => Promise<AgentPlaybook | null>;\n /** Optional callback the agent can use to fetch a compliance act by id mid-turn\n * (exposed via the `lookup_compliance_act` tool). */\n loadComplianceAct?: (actId: string) => Promise<AgentComplianceAct | null>;\n }\n): UseEditorAgentReturn {\n const config = useTiptapOfficeConfig();\n\n const [state, setState] = useState<AgentUIState>('IDLE');\n const [messages, setMessages] = useState<AgentChatMessage[]>([]);\n const [statusMessage, setStatusMessage] = useState('');\n const [errorMessage, setErrorMessage] = useState('');\n const [isPanelOpen, setIsPanelOpen] = useState(false);\n const [streamingMessageId, setStreamingMessageId] = useState<string | null>(null);\n const [historySessions, setHistorySessions] = useState<ChatSession[]>([]);\n const [isHistoryLoading, setIsHistoryLoading] = useState(false);\n const [provider, setProviderState] = useState<ProviderName>(config.defaultProvider);\n const [model, setModel] = useState<string>(config.defaultModel);\n const [journalVersion, setJournalVersion] = useState(0);\n const [lastTurnCostUsd, setLastTurnCostUsd] = useState<number | null>(null);\n const [cumulativeCostUsd, setCumulativeCostUsd] = useState(0);\n\n /** Local append-history call — pluggable via config; non-blocking. */\n const appendHistory = useCallback(\n async (chatId: string, msgs: ModelMessage[]) => {\n try {\n const init = await buildFetchInit(config, {\n method: 'POST',\n body: JSON.stringify({ messages: msgs }),\n });\n await fetch(`${config.apiBaseUrl}/editor/history/${chatId}/append`, init);\n } catch {\n // non-blocking\n }\n },\n [config],\n );\n\n const chatIdRef = useRef<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n /** Full SDK transcript — what we feed back into `runAgent` for follow-up turns. */\n const modelMessagesRef = useRef<ModelMessage[]>([]);\n /** Per-hook journal; persists across turns until startNewChat. */\n const journalRef = useRef<AgentJournal>(new AgentJournal());\n /** Section list cache, populated when the model calls `list_sections`. */\n const sectionCacheRef = useRef<Map<string, string>>(new Map());\n /** Comment/Suggestion refs mirror the latest options so tools read current values. */\n const commentsRef = useRef<Comment[]>(options?.comments ?? []);\n commentsRef.current = options?.comments ?? [];\n const suggestionsRef = useRef<Suggestion[]>(options?.suggestions ?? []);\n suggestionsRef.current = options?.suggestions ?? [];\n /** Playbook captured at submitPrompt; reused across clarification continuations. */\n const activePlaybookRef = useRef<AgentPlaybook | undefined>(undefined);\n\n // --- Provider switching ------------------------------------------------\n\n const setProvider = useCallback((p: ProviderName, m: string) => {\n setProviderState(p);\n setModel(m);\n }, []);\n\n // --- Session bootstrap -------------------------------------------------\n\n const ensureChatId = useCallback(async (): Promise<string | null> => {\n if (chatIdRef.current) return chatIdRef.current;\n if (!documentId) return null;\n try {\n const { chatId } = await createChatSession(config, documentId);\n chatIdRef.current = chatId;\n return chatId;\n } catch (err) {\n setErrorMessage(err instanceof Error ? err.message : 'Failed to create session');\n setState('ERROR');\n return null;\n }\n }, [config, documentId]);\n\n // --- Panel open/close --------------------------------------------------\n\n const openPanel = useCallback(() => {\n setIsPanelOpen(true);\n if (!chatIdRef.current && documentId) {\n setState('INITIALIZING');\n ensureChatId().then((id) => {\n if (id) setState('IDLE');\n });\n }\n }, [ensureChatId, documentId]);\n\n const closePanel = useCallback(() => {\n setIsPanelOpen(false);\n if (abortRef.current) {\n abortRef.current.abort();\n abortRef.current = null;\n }\n }, []);\n\n // --- Core turn driver --------------------------------------------------\n\n const runTurn = useCallback(\n async (turnMessages: ModelMessage[]) => {\n if (!editor) return;\n const chatId = await ensureChatId();\n if (!chatId) return;\n\n setState('RUNNING');\n setStatusMessage('');\n setErrorMessage('');\n\n // Per-turn buffers populated by tool side-effect callbacks.\n const turnNewComments: Comment[] = [];\n const turnNewCommentIds = new Set<string>();\n const turnResolvedIds: string[] = [];\n const turnResolvedIdSet = new Set<string>();\n\n // Placeholder assistant message; deltas accumulate into it.\n const assistantId = nextMessageId();\n const assistantState = {\n content: '',\n toolProgress: [] as AgentToolProgress[],\n clarificationQuestions: undefined as string[] | undefined,\n };\n setStreamingMessageId(assistantId);\n setMessages((prev) => [\n ...prev,\n {\n id: assistantId,\n role: 'assistant',\n content: '',\n timestamp: Date.now(),\n toolProgress: [],\n },\n ]);\n\n const pushAssistantUpdate = () => {\n setMessages((prev) =>\n prev.map((m) =>\n m.id === assistantId\n ? {\n ...m,\n content: assistantState.content,\n toolProgress: [...assistantState.toolProgress],\n clarificationQuestions: assistantState.clarificationQuestions,\n }\n : m,\n ),\n );\n };\n\n const handleStreamPart = (part: AgentStreamPart) => {\n switch (part.type) {\n case 'text-delta':\n assistantState.content += part.text;\n pushAssistantUpdate();\n break;\n case 'tool-call': {\n const label = labelForTool(\n part.toolName,\n part.input,\n sectionCacheRef.current,\n );\n assistantState.toolProgress.push({\n id: part.toolCallId,\n tool: part.toolName,\n label,\n status: 'running',\n });\n if (part.toolName === 'ask_user') {\n const args = part.input as { questions?: unknown };\n const qs = Array.isArray(args?.questions)\n ? args.questions.filter((q): q is string => typeof q === 'string')\n : [];\n if (qs.length > 0) {\n assistantState.clarificationQuestions = qs;\n }\n }\n pushAssistantUpdate();\n break;\n }\n case 'tool-result': {\n // Cache section titles when list_sections returns\n if (part.toolName === 'list_sections' && Array.isArray(part.output)) {\n for (const s of part.output as Array<{ id?: unknown; title?: unknown }>) {\n if (typeof s?.id === 'string' && typeof s?.title === 'string') {\n sectionCacheRef.current.set(s.id, s.title);\n }\n }\n }\n const idx = assistantState.toolProgress.findIndex(\n (t) => t.id === part.toolCallId,\n );\n if (idx >= 0) {\n const failed = isFailedToolResult(part.output);\n assistantState.toolProgress[idx] = {\n ...assistantState.toolProgress[idx],\n status: failed ? 'failed' : 'done',\n error: failed\n ? String((part.output as { error?: unknown })?.error ?? 'Failed')\n : undefined,\n };\n pushAssistantUpdate();\n }\n break;\n }\n case 'tool-error': {\n const idx = assistantState.toolProgress.findIndex(\n (t) => t.id === part.toolCallId,\n );\n if (idx >= 0) {\n assistantState.toolProgress[idx] = {\n ...assistantState.toolProgress[idx],\n status: 'failed',\n error:\n part.error instanceof Error\n ? part.error.message\n : String(part.error ?? 'Tool error'),\n };\n pushAssistantUpdate();\n }\n break;\n }\n default:\n break;\n }\n };\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n let askUserCalled = false;\n\n try {\n const result = await runAgent({\n config,\n editor,\n provider,\n model,\n chatId,\n messages: turnMessages,\n playbook: activePlaybookRef.current,\n loadPlaybook: options?.loadPlaybook,\n loadComplianceAct: options?.loadComplianceAct,\n journal: journalRef.current,\n getComments: () => commentsRef.current,\n getSuggestions: () => suggestionsRef.current,\n onNewComments: (comments) => {\n for (const c of comments) {\n if (turnNewCommentIds.has(c.id)) continue;\n turnNewCommentIds.add(c.id);\n turnNewComments.push(c);\n }\n },\n onResolvedComments: (ids) => {\n for (const id of ids) {\n if (turnResolvedIdSet.has(id)) continue;\n turnResolvedIdSet.add(id);\n turnResolvedIds.push(id);\n }\n },\n signal: controller.signal,\n onStreamPart: handleStreamPart,\n });\n\n modelMessagesRef.current = [...modelMessagesRef.current, ...result.responseMessages];\n askUserCalled = (assistantState.clarificationQuestions?.length ?? 0) > 0;\n\n await appendHistory(chatId, result.responseMessages);\n\n // Per-turn cost — non-blocking. The consumer's backend prices the\n // token counts the SDK reported. Failure (404, unknown model, 5xx)\n // just leaves the cost panel unchanged for this turn.\n void fetchTurnCost(config, {\n model,\n provider,\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n cachedInputTokens: result.usage.cachedInputTokens,\n reasoningTokens: result.usage.reasoningTokens,\n }).then((cost) => {\n if (cost === null) return;\n setLastTurnCostUsd(cost.total_cost_usd);\n setCumulativeCostUsd((prev) => prev + cost.total_cost_usd);\n });\n\n setStreamingMessageId(null);\n setJournalVersion((v) => v + 1);\n\n if (turnNewComments.length > 0 && options?.onAICommentsCreated) {\n options.onAICommentsCreated(turnNewComments);\n }\n if (turnResolvedIds.length > 0 && options?.onCommentsResolved) {\n options.onCommentsResolved(turnResolvedIds);\n }\n\n setState(askUserCalled ? 'AWAITING_USER' : 'IDLE');\n } catch (err) {\n setStreamingMessageId(null);\n if (controller.signal.aborted) {\n setState('IDLE');\n setStatusMessage('');\n return;\n }\n setErrorMessage(err instanceof Error ? err.message : 'Agent turn failed');\n setState('ERROR');\n } finally {\n if (abortRef.current === controller) abortRef.current = null;\n }\n },\n [config, editor, provider, model, ensureChatId, options, appendHistory],\n );\n\n // --- Submit prompt -----------------------------------------------------\n\n const submitPrompt = useCallback(\n (prompt: string, opts?: { playbook?: AgentPlaybook }) => {\n if (!editor) return;\n if (state === 'RUNNING' || state === 'INITIALIZING') return;\n\n const userMessage: AgentChatMessage = {\n id: nextMessageId(),\n role: 'user',\n content: prompt,\n timestamp: Date.now(),\n };\n setMessages((prev) => [...prev, userMessage]);\n\n const userModelMsg: ModelMessage = { role: 'user', content: prompt };\n modelMessagesRef.current = [...modelMessagesRef.current, userModelMsg];\n\n activePlaybookRef.current = opts?.playbook;\n\n void runTurn([...modelMessagesRef.current]);\n },\n [editor, state, runTurn],\n );\n\n // --- Clarification answer ---------------------------------------------\n\n const submitClarificationAnswer = useCallback(\n (answers: string[]) => {\n if (state !== 'AWAITING_USER') return;\n const combined = answers.join('\\n\\n');\n const userMessage: AgentChatMessage = {\n id: nextMessageId(),\n role: 'user',\n content: combined,\n timestamp: Date.now(),\n };\n setMessages((prev) => [...prev, userMessage]);\n\n const userModelMsg: ModelMessage = { role: 'user', content: combined };\n modelMessagesRef.current = [...modelMessagesRef.current, userModelMsg];\n\n void runTurn([...modelMessagesRef.current]);\n },\n [state, runTurn],\n );\n\n // --- Cancel -----------------------------------------------------------\n\n const cancel = useCallback(() => {\n if (abortRef.current) {\n abortRef.current.abort();\n abortRef.current = null;\n }\n setStreamingMessageId(null);\n setState('IDLE');\n setStatusMessage('');\n }, []);\n\n // --- New chat ---------------------------------------------------------\n\n const startNewChat = useCallback(() => {\n if (abortRef.current) {\n abortRef.current.abort();\n abortRef.current = null;\n }\n chatIdRef.current = null;\n modelMessagesRef.current = [];\n journalRef.current.clear();\n sectionCacheRef.current = new Map();\n activePlaybookRef.current = undefined;\n setMessages([]);\n setStatusMessage('');\n setErrorMessage('');\n setStreamingMessageId(null);\n setJournalVersion((v) => v + 1);\n setLastTurnCostUsd(null);\n setCumulativeCostUsd(0);\n setState('INITIALIZING');\n ensureChatId().then((id) => {\n if (id) setState('IDLE');\n });\n }, [ensureChatId]);\n\n // --- History list -----------------------------------------------------\n\n const fetchHistory = useCallback(async () => {\n setIsHistoryLoading(true);\n try {\n const data = await getSessionList(config, 0, 20);\n setHistorySessions(data.sessions);\n } catch {\n // non-critical\n } finally {\n setIsHistoryLoading(false);\n }\n }, [config]);\n\n // --- Load a past session ---------------------------------------------\n\n const loadSession = useCallback(\n async (sessionChatId: string) => {\n if (!editor) return;\n if (abortRef.current) {\n abortRef.current.abort();\n abortRef.current = null;\n }\n setState('INITIALIZING');\n setStatusMessage('Loading conversation...');\n setErrorMessage('');\n setStreamingMessageId(null);\n\n try {\n const data = await getChatMessages(config, sessionChatId);\n chatIdRef.current = sessionChatId;\n journalRef.current.clear();\n sectionCacheRef.current = new Map();\n setJournalVersion((v) => v + 1);\n\n // Today's backend returns the legacy `{ text, sentBy }` shape; the new\n // backend will return ModelMessage[] directly. Project either into both\n // the UI list and the SDK transcript so the next turn continues.\n const legacy = data.messages;\n const uiMessages: AgentChatMessage[] = [];\n const sdkMessages: ModelMessage[] = [];\n for (const m of legacy) {\n const role: 'user' | 'assistant' = m.sentBy === 'USER' ? 'user' : 'assistant';\n uiMessages.push({\n id: m.messageId,\n role,\n content: m.text,\n timestamp: new Date(m.timestamp).getTime(),\n });\n sdkMessages.push({ role, content: m.text } as ModelMessage);\n }\n setMessages(uiMessages);\n modelMessagesRef.current = sdkMessages;\n\n setStatusMessage('');\n setState('IDLE');\n } catch (err) {\n setErrorMessage(err instanceof Error ? err.message : 'Failed to load session');\n setState('ERROR');\n }\n },\n [config, editor],\n );\n\n // --- Cleanup ----------------------------------------------------------\n\n useEffect(() => {\n return () => {\n if (abortRef.current) abortRef.current.abort();\n };\n }, []);\n\n // `journalVersion` is read here purely to re-render when it changes.\n void journalVersion;\n const activeChanges = journalRef.current.list(true);\n\n return {\n state,\n messages,\n statusMessage,\n errorMessage,\n isPanelOpen,\n streamingMessageId,\n activeChanges,\n provider,\n model,\n setProvider,\n lastTurnCostUsd,\n cumulativeCostUsd,\n openPanel,\n closePanel,\n submitPrompt,\n submitClarificationAnswer,\n cancel,\n startNewChat,\n historySessions,\n isHistoryLoading,\n fetchHistory,\n loadSession,\n };\n}\n","/**\n * Agent driver — see spec §7.1.\n *\n * Wires provider + tools + system prompt and streams `result.fullStream` to the\n * caller. Returns the final `response.messages` array so the caller can\n * persist the transcript.\n */\n\nimport {\n streamText,\n stepCountIs,\n type ModelMessage,\n type TextStreamPart,\n type ToolSet,\n} from 'ai';\nimport type { Editor } from '@tiptap/react';\n\nimport { providerFor } from './providers';\nimport { buildSystemPrompt } from './systemPrompt';\nimport { buildEditorTools } from './tools';\nimport type { AgentJournal } from './journal';\nimport type {\n AgentPlaybook,\n AgentComplianceAct,\n} from './types';\nimport type { Comment, Suggestion } from '../types';\nimport type { TiptapOfficeConfig, ProviderName } from '../config/TiptapOfficeProvider';\n\nexport type AgentStreamPart = TextStreamPart<ToolSet>;\n\nexport interface RunAgentArgs {\n config: TiptapOfficeConfig;\n editor: Editor;\n provider: ProviderName;\n model: string;\n chatId: string;\n messages: ModelMessage[];\n playbook?: AgentPlaybook;\n complianceActs?: AgentComplianceAct[];\n journal: AgentJournal;\n getComments: () => Comment[];\n getSuggestions: () => Suggestion[];\n loadPlaybook?: (playbookId: string) => Promise<AgentPlaybook | null>;\n loadComplianceAct?: (actId: string) => Promise<AgentComplianceAct | null>;\n onNewComments?: (comments: Comment[]) => void;\n onResolvedComments?: (ids: string[]) => void;\n signal: AbortSignal;\n onStreamPart: (part: AgentStreamPart) => void;\n}\n\n/**\n * Aggregated token usage for a single agent turn. Mirrors the SDK's `LanguageModelUsage`\n * shape (`inputTokens` + `outputTokens` + optional cached/reasoning) so the caller can\n * pass it straight to `/llm/cost`. Returned even when the turn ends in error — partial\n * usage still has billable cost.\n */\nexport interface AgentTurnUsage {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n reasoningTokens: number;\n}\n\nexport interface RunAgentResult {\n /** Assistant + tool messages produced by this turn — caller appends to chat history. */\n responseMessages: ModelMessage[];\n /** Aggregated token usage for the turn (across all agent-loop steps). */\n usage: AgentTurnUsage;\n}\n\nexport async function runAgent(args: RunAgentArgs): Promise<RunAgentResult> {\n const tools = buildEditorTools({\n editor: args.editor,\n journal: args.journal,\n getComments: args.getComments,\n getSuggestions: args.getSuggestions,\n loadPlaybook: args.loadPlaybook,\n loadComplianceAct: args.loadComplianceAct,\n onNewComments: args.onNewComments,\n onResolvedComments: args.onResolvedComments,\n });\n\n const providerFactory = providerFor(args.config, args.provider, args.chatId);\n // Each provider factory is callable as `(modelId) => LanguageModelV3`.\n const model = providerFactory(args.model);\n\n const result = streamText({\n model,\n system: buildSystemPrompt({\n playbook: args.playbook,\n complianceActs: args.complianceActs,\n }),\n tools,\n messages: args.messages,\n stopWhen: stepCountIs(20),\n toolChoice: 'auto',\n abortSignal: args.signal,\n });\n\n for await (const part of result.fullStream) {\n args.onStreamPart(part);\n }\n\n const response = await result.response;\n const usage = await result.usage;\n return {\n responseMessages: response.messages,\n usage: {\n inputTokens: usage.inputTokens ?? 0,\n outputTokens: usage.outputTokens ?? 0,\n cachedInputTokens: usage.cachedInputTokens ?? 0,\n reasoningTokens: usage.reasoningTokens ?? 0,\n },\n };\n}\n","/**\n * Per-provider factories routed through the consumer's backend LLM proxy.\n *\n * The browser never holds an API key — `apiKey: 'proxied'` is a placeholder\n * that satisfies the AI SDK's type constraints. Your proxy strips inbound\n * `Authorization` headers and injects the real provider key server-side.\n *\n * All URL + header behaviour comes from `TiptapOfficeConfig`. The library\n * itself bakes in no domains, no env-var lookups, and no header names.\n */\n\nimport { createAnthropic, type AnthropicProvider } from '@ai-sdk/anthropic';\nimport { createOpenAI, type OpenAIProvider } from '@ai-sdk/openai';\nimport {\n createGoogleGenerativeAI,\n type GoogleGenerativeAIProvider,\n} from '@ai-sdk/google';\nimport type { TiptapOfficeConfig, ProviderName } from '../config/TiptapOfficeProvider';\n\nexport type AnyProvider =\n | AnthropicProvider\n | OpenAIProvider\n | GoogleGenerativeAIProvider;\n\ntype ProxiedFetch = (\n input: RequestInfo | URL,\n init?: RequestInit,\n) => Promise<Response>;\n\nfunction makeFetch(config: TiptapOfficeConfig): ProxiedFetch {\n const credentials = config.includeCredentials ?? 'include';\n return (input, init) => fetch(input, { ...(init ?? {}), credentials });\n}\n\n/**\n * Build a provider factory pointing at the proxy. The returned value is\n * callable as `provider(modelId)` and yields a LanguageModelV3-compatible\n * model.\n */\nexport function providerFor(\n config: TiptapOfficeConfig,\n name: ProviderName,\n chatId: string,\n): AnyProvider {\n const proxyBase = `${config.apiBaseUrl}${config.llmProxyPath ?? '/llm/proxy'}`;\n const headers = config.getProxyHeaders\n ? config.getProxyHeaders({ provider: name, chatId })\n : {};\n const fetchImpl = makeFetch(config);\n\n switch (name) {\n case 'anthropic':\n return createAnthropic({\n baseURL: proxyBase,\n apiKey: 'proxied',\n headers,\n fetch: fetchImpl,\n });\n case 'openai':\n return createOpenAI({\n baseURL: proxyBase,\n apiKey: 'proxied',\n headers,\n fetch: fetchImpl,\n });\n case 'google':\n return createGoogleGenerativeAI({\n baseURL: proxyBase,\n apiKey: 'proxied',\n headers,\n fetch: fetchImpl,\n });\n }\n}\n","/**\n * System prompt for the editor agent.\n *\n * Documents are exposed as ID-annotated HTML; the model emits HTML in edit-tool\n * content fields. Every TipTap extension's `parseHTML`/`renderHTML` handles\n * round-trip fidelity (color, font, highlight, strike, code, alignment, indent,\n * rowspan) — no bespoke per-feature parsing.\n */\n\nimport type { AgentPlaybook, AgentComplianceAct } from './types';\n\nexport interface BuildSystemPromptArgs {\n playbook?: AgentPlaybook;\n complianceActs?: AgentComplianceAct[];\n}\n\nexport function buildSystemPrompt(args: BuildSystemPromptArgs = {}): string {\n const { playbook, complianceActs } = args;\n const parts: string[] = [];\n\n parts.push(\n 'You are a document editing assistant. You collaborate with the user by ' +\n 'inspecting the live document and proposing edits through structured tool calls. ' +\n 'Edits land as tracked changes the user reviews; never destructive writes.',\n );\n\n parts.push(\n [\n '## Document representation',\n 'The document is exposed as ID-annotated HTML. Every block element (paragraph,',\n 'heading, list item, table, table cell) carries `data-synk-id=\"p:xxxx\"` (or `t:`,',\n '`c:`) on its outer tag — for example:',\n '',\n ' <p data-synk-id=\"p:7a3f\">A clause.</p>',\n ' <h2 data-synk-id=\"p:8x2a\">Section title</h2>',\n ' <li data-synk-id=\"p:9c4f\">List item content</li>',\n ' <td data-synk-id=\"c:3f7b\">Cell content</td>',\n '',\n 'These synkIds are the only valid `target` values for edit tools. IDs are',\n 'regenerated across sessions; never reuse an id from prior conversations.',\n '',\n '**Never invent a `data-synk-id` value.** When inserting a new node, call',\n '`mint_node_id` first and use the returned id. When editing an existing node,',\n 'use the id from the most recent `read_section` for that section.',\n ].join('\\n'),\n );\n\n parts.push(\n [\n '## Tool usage protocol',\n '1. Start every turn with `list_sections` unless the user clearly targeted one section.',\n '2. Always call `read_section` before editing any section — synkIds change across sessions and you must work from current state.',\n '3. Before any `insert_after` / `insert_before` / `insert_table` / `insert_row` / `insert_column` op, call `mint_node_id` to obtain a fresh synkId for the new node.',\n '4. Prefer the smallest tool for the job. `replace_text` over `replace_paragraph` when you only need to change a substring.',\n '5. `replace_section` is intentionally unavailable. To rewrite a section, decompose into per-paragraph `delete` + `insert_after` ops.',\n '6. Use `ask_user` only when truly blocked on a substantive choice — not for confirmation.',\n '7. To inspect or undo your own edits this turn, call `list_my_changes` / `revert_change`.',\n ].join('\\n'),\n );\n\n parts.push(\n [\n '## Content formatting',\n 'Inside `content` / `replace` fields, emit HTML fragments using these tags:',\n '',\n '**Inline marks**',\n '- `<strong>bold</strong>`',\n '- `<em>italic</em>`',\n '- `<u>underline</u>`',\n '- `<s>strike</s>`',\n '- `<code>inline code</code>`',\n '- `<mark style=\"background-color:#ffeb3b\">highlighted</mark>`',\n '- `<span style=\"color:#ff0000\">colored text</span>`',\n '- `<span style=\"font-family:\\'Times New Roman\\',serif\">named font</span>`',\n '- `<a href=\"https://...\">link</a>` (only when the document already contains links)',\n '',\n '**Block elements**',\n '- `<p data-synk-id=\"p:xxxx\">…</p>` (paragraph)',\n '- `<h1>`–`<h6>` with `data-synk-id` on the heading',\n '- `<li data-synk-id=\"p:xxxx\">…</li>` inside `<ul>` or `<ol>`',\n '- `<blockquote data-synk-id=\"p:xxxx\"><p>…</p></blockquote>`',\n '- `<pre data-synk-id=\"p:xxxx\"><code class=\"language-…\">…</code></pre>`',\n '- `<hr data-synk-id=\"p:xxxx\">`',\n '- `<table data-synk-id=\"t:xxxx\">` containing `<tr>` containing `<th>`/`<td>` with `data-synk-id=\"c:xxxx\"`, and `colspan`/`rowspan` when needed',\n '',\n '**Block-level attributes**',\n '- Alignment: `style=\"text-align:left|center|right|justify\"`',\n '- Indent depth: `data-indent=\"N\"` (N is a positive integer)',\n '',\n '**Hard formatting rules**',\n '- Emit fragments only. Never wrap output in `<!doctype>`, `<html>`, `<head>`, `<body>`, or `<!CDATA>`.',\n '- Do not wrap the HTML in backticks or a markdown code fence. Tool args expect raw HTML.',\n '- When replacing an existing node, keep its existing `data-synk-id` on the outer tag.',\n '- When inserting a new node, the outer tag\\'s `data-synk-id` must come from `mint_node_id`.',\n '- Do not output `<ins>`, `<del>`, or `<span data-type=\"modification\">` elements. Those are editor chrome you only see when reading; the system manages them.',\n ].join('\\n'),\n );\n\n parts.push(\n [\n '## Hard rules',\n '- Never invent a synkId. If an edit tool returns `{ ok: false, error: \"Node not found\" }` or similar, call `read_section` again for the relevant section and retry with the current synkId.',\n '- Never claim an edit was made unless the corresponding tool call returned `{ ok: true }`.',\n '- When `read_section` returns comments or suggestions, treat them as authoritative context for that section.',\n '- Keep `reasoning` strings to one short sentence — they surface as inline comments on the affected node.',\n ].join('\\n'),\n );\n\n if (playbook) {\n parts.push(\n [\n `## Playbook: ${playbook.title}`,\n 'Apply the following rules to any edit you make in this turn:',\n '',\n playbook.content,\n ].join('\\n'),\n );\n }\n\n if (complianceActs && complianceActs.length > 0) {\n const lines = ['## Compliance acts in scope'];\n for (const act of complianceActs) {\n lines.push(`- ${act.title} (${act.id})${act.description ? ` — ${act.description}` : ''}`);\n }\n parts.push(lines.join('\\n'));\n }\n\n return parts.join('\\n\\n');\n}\n","/**\n * Editor agent tool surface — see spec §6.\n *\n * Every edit tool is a thin wrapper over `applySingleOp` (or a bypass-dispatch\n * variant for structural ops). Failures are returned to the model, never thrown.\n */\n\nimport { tool } from 'ai';\nimport { z } from 'zod';\nimport type { Editor } from '@tiptap/react';\nimport type { Transaction } from '@tiptap/pm/state';\n\nimport {\n applySingleOp,\n addReasoningComments,\n applyAddCommentMarks,\n operationKey,\n} from '../utils/editApplicator';\nimport { detectSections } from '../utils/sectionDetector';\nimport { collectDocumentStyles } from '../utils/contentSerializer';\nimport { serializeSection } from './htmlSerializer';\nimport {\n buildAnnotationsPayload,\n collectSynkIdsInRange,\n} from '../utils/annotationSerializer';\nimport {\n generateUniqueNodeId,\n collectAllSynkIds,\n} from '../utils/nodeIdUtils';\nimport { suggestChangesKey } from '../extensions/suggestionMode';\n\nimport type {\n EditOperation,\n EditOperationWithStatus,\n} from '../types/editOperations';\nimport type { Comment, Suggestion } from '../types';\nimport type { AgentJournal } from './journal';\nimport type { AgentPlaybook, AgentComplianceAct } from './types';\nimport { collectSuggestionIds, diffSuggestionIds } from './changeTracking';\nimport { computeInverse } from './inverseOps';\n\nexport interface BuildEditorToolsArgs {\n editor: Editor;\n journal: AgentJournal;\n getComments: () => Comment[];\n getSuggestions: () => Suggestion[];\n /** Loaders for playbook and compliance act content (optional). */\n loadPlaybook?: (playbookId: string) => Promise<AgentPlaybook | null>;\n loadComplianceAct?: (actId: string) => Promise<AgentComplianceAct | null>;\n /** Side-effect sinks for comments produced by content ops. */\n onNewComments?: (comments: Comment[]) => void;\n onResolvedComments?: (ids: string[]) => void;\n}\n\n/** Outcome shape returned to the model from every edit tool. */\ntype EditResult =\n | { ok: true; change_id: string; operation_key: string }\n | { ok: false; error: string };\n\nconst STRUCTURAL_OP_TYPES = new Set<EditOperation['type']>([\n 'insert_row',\n 'delete_row',\n 'insert_column',\n 'delete_column',\n 'insert_table',\n 'replace_table',\n]);\n\n/** Hints baked into tool field descriptions so the model emits the right syntax. */\nconst INLINE_FORMAT_HINT =\n 'HTML inline fragment. Use standard tags: <strong>, <em>, <u>, <s>, <code>, <a href>, <mark>, <span style=\"color:…\">, <span style=\"font-family:…\">.';\n\nconst BLOCK_FORMAT_HINT =\n 'HTML block element with data-synk-id on the outer tag, e.g. <p data-synk-id=\"p:xxxx\">…</p> or <h2 data-synk-id=\"p:xxxx\">…</h2> or <li data-synk-id=\"p:xxxx\">…</li>. Use standard inline tags inside.';\n\nconst READ_SECTION_DESCRIPTION =\n 'Read a section as ID-annotated HTML, together with any open comments and pending suggestions anchored to nodes inside it. Each block element carries `data-synk-id=\"p:xxxx\"` (or `t:`, `c:`) — these are the synkIds you target in edit operations.';\n\nexport function buildEditorTools(args: BuildEditorToolsArgs) {\n const { editor, journal, getComments, getSuggestions } = args;\n\n /**\n * Run a structural (suggestion-mode-bypassing) op. Temporarily wraps\n * `view.dispatch` so the transaction emitted by `applySingleOp` carries\n * the `{ skip: true }` meta the suggest-changes plugin watches for.\n */\n function applyStructuralOp(op: EditOperation): EditOperationWithStatus {\n const view = editor.view;\n const wrappedDispatch = view.dispatch.bind(view);\n const interceptor = (tr: Transaction) => {\n tr.setMeta(suggestChangesKey, { skip: true });\n wrappedDispatch(tr);\n };\n view.dispatch = interceptor as typeof view.dispatch;\n try {\n return applySingleOp(editor, op as EditOperationWithStatus);\n } finally {\n view.dispatch = wrappedDispatch;\n }\n }\n\n /** Shared executor used by every edit tool. */\n function runEditOp(op: EditOperation): EditResult {\n const isStructural = STRUCTURAL_OP_TYPES.has(op.type);\n const docBefore = editor.state.doc;\n const idsBefore = isStructural ? null : collectSuggestionIds(docBefore);\n\n let inverseOp: EditOperation | null = null;\n if (isStructural) {\n inverseOp = computeInverse(op, docBefore);\n }\n\n let result: EditOperationWithStatus;\n try {\n result = isStructural ? applyStructuralOp(op) : applySingleOp(editor, op as EditOperationWithStatus);\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n if (result.status !== 'applied') {\n return { ok: false, error: result.error ?? 'Failed' };\n }\n\n let recorded;\n if (isStructural) {\n recorded = journal.record({\n tool: op.type,\n args: op,\n inverseOp: inverseOp ?? undefined,\n });\n } else {\n const idsAfter = collectSuggestionIds(editor.state.doc);\n const newIds = diffSuggestionIds(idsBefore ?? new Set(), idsAfter);\n recorded = journal.record({\n tool: op.type,\n args: op,\n suggestionIds: newIds,\n });\n }\n\n // Post-apply hooks for content ops\n if (op.type === 'add_comment') {\n const { newComments, resolvedCommentIds } = applyAddCommentMarks(editor, [result]);\n if (newComments.length > 0) args.onNewComments?.(newComments);\n if (resolvedCommentIds.length > 0) args.onResolvedComments?.(resolvedCommentIds);\n } else if (!isStructural && op.type !== 'delete') {\n // addReasoningComments self-filters via getCommentTargetId, but skipping\n // delete here avoids the extra no-op transaction.\n const reasoningComments = addReasoningComments(editor, [result]);\n if (reasoningComments.length > 0) args.onNewComments?.(reasoningComments);\n }\n\n return {\n ok: true,\n change_id: recorded.id,\n operation_key: operationKey(result),\n };\n }\n\n // ── Readers ────────────────────────────────────────────────────────────────\n\n const list_sections = tool({\n description:\n 'List every section in the document with id, title, heading level, and parent section id. Call this first unless the user clearly targeted one section.',\n inputSchema: z.object({}),\n execute: async () =>\n detectSections(editor.state.doc).map((s) => ({\n id: s.id,\n title: s.title,\n level: s.level,\n parent_id: s.parentId,\n })),\n });\n\n const read_section = tool({\n description: READ_SECTION_DESCRIPTION,\n inputSchema: z.object({\n section_id: z.string().describe('Section id from list_sections (e.g. synk-section-3)'),\n }),\n execute: async ({ section_id }) => {\n const section = detectSections(editor.state.doc).find((s) => s.id === section_id);\n if (!section) return { ok: false as const, error: 'Section not found' };\n\n const content = serializeSection(editor.state.doc, section);\n const full = buildAnnotationsPayload(editor.state.doc, getComments(), getSuggestions());\n const idsInRange = collectSynkIdsInRange(editor.state.doc, section.startPos, section.endPos);\n const comments = full.comments.filter((c) => idsInRange.has(c.targetSynkId));\n const suggestions = full.suggestions.filter((s) => idsInRange.has(s.targetSynkId));\n return { ok: true as const, content, comments, suggestions };\n },\n });\n\n const read_document_styles = tool({\n description:\n 'Return the document\\'s dominant font family and text alignment so generated content can match.',\n inputSchema: z.object({}),\n execute: async () => collectDocumentStyles(editor.state.doc),\n });\n\n const mint_node_id = tool({\n description:\n 'Generate a unique synkId for a new node before calling insert_after / insert_before / insert_table / insert_row / insert_column. Returns a string like \"p:7a3f\", \"t:8x2a\", or \"c:3f7b\".',\n inputSchema: z.object({\n node_type: z.enum(['paragraph', 'heading', 'listItem', 'table', 'tableCell']),\n }),\n execute: async ({ node_type }) => ({\n id: generateUniqueNodeId(node_type, collectAllSynkIds(editor.state.doc)),\n }),\n });\n\n // ── Edit tools (content ops) ───────────────────────────────────────────────\n\n const replace_text = tool({\n description:\n 'Replace a substring inside the paragraph or table cell identified by synkId.',\n inputSchema: z.object({\n target: z.string().describe('synkId, e.g. p:7a3f or c:3f7b'),\n find: z.string(),\n replace: z.string().describe(`Replacement text. ${INLINE_FORMAT_HINT}`),\n reasoning: z.string().describe('One short sentence justifying the edit. Surfaces as an inline comment.'),\n }),\n execute: async (input) => runEditOp({ type: 'replace_text', ...input }),\n });\n\n const replace_paragraph = tool({\n description: `Replace the entire contents of a paragraph or heading by synkId. To change the block type, emit a different block element. ${BLOCK_FORMAT_HINT}`,\n inputSchema: z.object({\n target: z.string(),\n content: z.string(),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'replace_paragraph', ...input }),\n });\n\n const insert_after = tool({\n description: `Insert a new block after the node identified by \\`target\\`. Call mint_node_id first to obtain \\`new_id\\`. ${BLOCK_FORMAT_HINT}`,\n inputSchema: z.object({\n target: z.string(),\n new_id: z.string(),\n content: z.string(),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'insert_after', ...input }),\n });\n\n const insert_before = tool({\n description: `Insert a new block before the node identified by \\`target\\`. Call mint_node_id first to obtain \\`new_id\\`. ${BLOCK_FORMAT_HINT}`,\n inputSchema: z.object({\n target: z.string(),\n new_id: z.string(),\n content: z.string(),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'insert_before', ...input }),\n });\n\n const delete_node = tool({\n description:\n 'Delete the paragraph or table identified by synkId.',\n inputSchema: z.object({\n target: z.string(),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'delete', ...input }),\n });\n\n const replace_cell = tool({\n description:\n 'Replace the contents of a table cell. Use `content` for a single-paragraph cell or `paragraphs` for a multi-paragraph cell.',\n inputSchema: z.object({\n target: z.string().describe('Cell synkId (c:xxxx)'),\n content: z.string().optional(),\n paragraphs: z\n .array(z.object({ id: z.string(), content: z.string() }))\n .optional(),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'replace_cell', ...input }),\n });\n\n const add_comment = tool({\n description:\n 'Attach a review comment to a node without modifying its content.',\n inputSchema: z.object({\n target: z.string(),\n comment_text: z.string(),\n comment_author: z.string(),\n comment_severity: z.enum(['critical', 'major', 'minor', 'info']),\n comment_act: z.string().describe('Compliance act id or comma-separated list (e.g. \"gdpr\", \"ccpa\") — resolved by the consumer'),\n comment_article: z.string().describe('e.g. \"Article 6(1)\"'),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'add_comment', ...input }),\n });\n\n // ── Edit tools (structural ops, bypass suggestion mode) ────────────────────\n\n const insert_row = tool({\n description: 'Insert a row into a table after the given row index (0-based).',\n inputSchema: z.object({\n table: z.string(),\n after_row: z.number().int().min(-1),\n cells: z.array(z.object({ id: z.string(), content: z.string() })),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'insert_row', ...input }),\n });\n\n const delete_row = tool({\n description: 'Delete a row from a table at the given row index (0-based).',\n inputSchema: z.object({\n table: z.string(),\n row: z.number().int().min(0),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'delete_row', ...input }),\n });\n\n const insert_column = tool({\n description:\n 'Insert a column into a table after the given column index (0-based). Provide a header cell plus one cell per data row.',\n inputSchema: z.object({\n table: z.string(),\n after_column: z.number().int().min(-1),\n header: z.object({ id: z.string(), content: z.string() }),\n cells: z.array(z.object({ id: z.string(), content: z.string() })),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'insert_column', ...input }),\n });\n\n const delete_column = tool({\n description: 'Delete a column from a table at the given column index (0-based).',\n inputSchema: z.object({\n table: z.string(),\n column: z.number().int().min(0),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'delete_column', ...input }),\n });\n\n const insert_table = tool({\n description:\n 'Insert a new table after the node identified by `after`. Call mint_node_id first for `table_id` and for each header/cell id.',\n inputSchema: z.object({\n after: z.string(),\n table_id: z.string(),\n headers: z.array(z.object({ id: z.string(), content: z.string() })),\n rows: z.array(z.array(z.object({ id: z.string(), content: z.string() }))),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'insert_table', ...input }),\n });\n\n const replace_table = tool({\n description: 'Replace an existing table\\'s headers and rows wholesale.',\n inputSchema: z.object({\n target: z.string(),\n headers: z.array(z.object({ id: z.string(), content: z.string() })),\n rows: z.array(z.array(z.object({ id: z.string(), content: z.string() }))),\n reasoning: z.string(),\n }),\n execute: async (input) => runEditOp({ type: 'replace_table', ...input }),\n });\n\n // ── Meta tools ─────────────────────────────────────────────────────────────\n\n const list_my_changes = tool({\n description:\n 'List edits you have made in this conversation that have not yet been reverted. Returns agent change ids you can pass to revert_change.',\n inputSchema: z.object({}),\n execute: async () =>\n journal.list(true).map((c) => ({\n id: c.id,\n tool: c.tool,\n args: c.args,\n applied_at: c.appliedAt,\n })),\n });\n\n const revert_change = tool({\n description:\n 'Revert a specific edit you made earlier. Pass the id from list_my_changes. Deterministic: rejects the underlying tracked suggestions or applies the stored inverse op.',\n inputSchema: z.object({\n change_id: z.string(),\n reasoning: z.string(),\n }),\n execute: async ({ change_id }) => {\n const result = journal.revert(change_id, editor);\n return result.ok ? { ok: true as const } : { ok: false as const, error: result.error ?? 'Failed' };\n },\n });\n\n const ask_user = tool({\n description:\n 'Pause and ask the user one or more clarification questions before continuing. Use only when truly blocked on a substantive choice.',\n inputSchema: z.object({\n questions: z.array(z.string()).min(1).max(5),\n }),\n // No execute: the UI catches this tool call and resumes the agent loop\n // after the user submits answers.\n });\n\n const lookup_playbook = tool({\n description: 'Fetch a playbook (set of drafting/review rules) by id.',\n inputSchema: z.object({ playbook_id: z.string() }),\n execute: async ({ playbook_id }) => {\n if (!args.loadPlaybook) return { ok: false as const, error: 'Playbook lookup not configured' };\n try {\n const pb = await args.loadPlaybook(playbook_id);\n if (!pb) return { ok: false as const, error: 'Playbook not found' };\n return { ok: true as const, playbook: pb };\n } catch (err) {\n return { ok: false as const, error: err instanceof Error ? err.message : String(err) };\n }\n },\n });\n\n const lookup_compliance_act = tool({\n description: 'Fetch the articles of a compliance act by id. Resolved by the consumer-supplied loadComplianceAct callback.',\n inputSchema: z.object({ act_id: z.string() }),\n execute: async ({ act_id }) => {\n if (!args.loadComplianceAct) return { ok: false as const, error: 'Compliance act lookup not configured' };\n try {\n const act = await args.loadComplianceAct(act_id);\n if (!act) return { ok: false as const, error: 'Act not found' };\n return { ok: true as const, act };\n } catch (err) {\n return { ok: false as const, error: err instanceof Error ? err.message : String(err) };\n }\n },\n });\n\n return {\n list_sections,\n read_section,\n read_document_styles,\n mint_node_id,\n replace_text,\n replace_paragraph,\n insert_after,\n insert_before,\n delete_node,\n replace_cell,\n add_comment,\n insert_row,\n delete_row,\n insert_column,\n delete_column,\n insert_table,\n replace_table,\n list_my_changes,\n revert_change,\n ask_user,\n lookup_playbook,\n lookup_compliance_act,\n };\n}\n\nexport type EditorTools = ReturnType<typeof buildEditorTools>;\n","/**\n * HTML parser for the editor agent.\n *\n * Mirrors the markdown parsers in `utils/markdownToProseMirror.ts` (return\n * shape: `ProseMirrorNode[]`) so the editApplicator boundary can swap one for\n * the other based on `NEXT_PUBLIC_AGENT_HTML`.\n *\n * Under the hood: TipTap's `DOMParser.fromSchema` uses each extension's\n * `parseHTML` rules — color, font, highlight, strike, code, alignment,\n * indent, rowspan, and any future extension are handled automatically. No\n * bespoke per-feature parsing.\n */\n\nimport {\n DOMParser as PMDOMParser,\n type Node as PMNode,\n type Schema,\n} from '@tiptap/pm/model';\n\nimport { NODE_ID_ATTR } from '../utils/nodeIdUtils';\n\n/**\n * Parse an inline HTML fragment (text + inline marks) into ProseMirror inline\n * nodes. Wraps in a `<p>` so the schema knows to expect inline content, then\n * extracts the paragraph's children.\n *\n * Used wherever the markdown path would have called `parseInlineMarkdown`.\n */\nexport function parseInlineHtml(html: string, schema: Schema): PMNode[] {\n if (!html) return [];\n const fragment = parseInDom(`<p>${stripDocumentWrappers(html)}</p>`, schema);\n const paragraph = fragment.firstChild;\n if (!paragraph) return [];\n const nodes: PMNode[] = [];\n paragraph.forEach((child) => nodes.push(child));\n return nodes;\n}\n\n/**\n * Parse a block-level HTML fragment into ProseMirror block nodes.\n *\n * Used wherever the markdown path would have called `parseAnnotatedMarkdown`.\n */\nexport function parseBlockHtml(html: string, schema: Schema): PMNode[] {\n if (!html) return [];\n const fragment = parseInDom(stripDocumentWrappers(html), schema);\n const nodes: PMNode[] = [];\n fragment.forEach((child) => nodes.push(child));\n return nodes;\n}\n\n/**\n * Set `synkId` on a node if it isn't already set (or differs). Returns a new\n * node with the merged attrs; preserves content and marks.\n *\n * Use when the agent supplies HTML content for a new node — the model emits\n * `mint_node_id` then passes that id alongside the HTML, but the HTML it\n * emits may or may not have `data-synk-id` set on the outer element.\n */\nexport function injectSynkId(node: PMNode, synkId: string): PMNode {\n if (node.attrs[NODE_ID_ATTR] === synkId) return node;\n return node.type.create(\n { ...node.attrs, [NODE_ID_ATTR]: synkId },\n node.content,\n node.marks,\n );\n}\n\nfunction parseInDom(html: string, schema: Schema): PMNode {\n const dom = new globalThis.DOMParser().parseFromString(\n `<div>${html}</div>`,\n 'text/html',\n );\n const container = dom.body.firstElementChild;\n if (!container) {\n // Empty input → return an empty doc-like node.\n return PMDOMParser.fromSchema(schema).parse(\n dom.createElement('div'),\n );\n }\n return PMDOMParser.fromSchema(schema).parse(container);\n}\n\n/**\n * Strip wrappers the model may emit despite the system prompt forbidding them.\n * Defensive only — if the agent obeys the prompt, this is a no-op.\n */\nfunction stripDocumentWrappers(html: string): string {\n return html\n .replace(/<!doctype[^>]*>/gi, '')\n .replace(/<\\/?(?:html|head|body|meta|title)[^>]*>/gi, '')\n .trim();\n}\n","/**\n * Edit applicator — converts AI edit operations into a single ProseMirror transaction.\n * Implements all 13 operation types from ADR-014.\n */\n\nimport type { Editor } from '@tiptap/react';\nimport type { Node as ProseMirrorNode, Schema } from '@tiptap/pm/model';\nimport type { Transaction } from '@tiptap/pm/state';\nimport type {\n EditOperationWithStatus,\n ReplaceTextOp,\n ReplaceParagraphOp,\n InsertAfterOp,\n InsertBeforeOp,\n DeleteOp,\n ReplaceSectionOp,\n AddCommentOp,\n ReplaceCellOp,\n InsertRowOp,\n DeleteRowOp,\n InsertColumnOp,\n DeleteColumnOp,\n InsertTableOp,\n ReplaceTableOp,\n} from '../types/editOperations';\nimport type { Comment } from '../types';\nimport { findNodeBySynkId, NODE_ID_ATTR } from './nodeIdUtils';\nimport {\n parseInlineHtml,\n parseBlockHtml,\n injectSynkId,\n} from '../agent/htmlParser';\n\n/**\n * Content fields on edit ops carry HTML fragments (see\n * `docs/superpowers/specs/2026-05-15-editor-html-representation.md`).\n * These thin aliases keep call sites readable.\n */\nfunction parseInline(text: string, schema: Schema): ProseMirrorNode[] {\n return text ? parseInlineHtml(text, schema) : [];\n}\n\nfunction parseBlock(text: string, schema: Schema): ProseMirrorNode[] {\n return text ? parseBlockHtml(text, schema) : [];\n}\n\ninterface NodeResult {\n node: ProseMirrorNode;\n pos: number;\n}\n\n/**\n * Find a node by synkId, falling back to the first paragraph in the document\n * when the operation targets a backend-generated placeholder for an empty section.\n */\nfunction findTargetNode(\n doc: ProseMirrorNode,\n synkId: string,\n op: EditOperationWithStatus\n): NodeResult | null {\n const found = findNodeBySynkId(doc, synkId);\n if (found) return found;\n\n // If the backend signals this was an empty-section placeholder,\n // resolve to the first paragraph in the doc as a fallback.\n if (op.empty_section_placeholder) {\n let fallback: NodeResult | null = null;\n doc.descendants((node, pos) => {\n if (fallback) return false;\n if (node.type.name === 'paragraph') {\n fallback = { node, pos };\n return false;\n }\n });\n return fallback;\n }\n\n return null;\n}\n\n/**\n * Apply a list of edit operations as a single ProseMirror transaction.\n * One Ctrl+Z undoes the entire edit plan atomically.\n * Returns the list of operations with updated status.\n */\nexport function applyEditPlan(\n editor: Editor,\n operations: EditOperationWithStatus[]\n): EditOperationWithStatus[] {\n const { state } = editor;\n const tr = state.tr;\n\n for (const op of operations) {\n if (op.status === 'skipped') continue;\n\n try {\n switch (op.type) {\n case 'replace_text':\n applyReplaceText(tr, state.doc, state.schema, op);\n break;\n case 'replace_paragraph':\n applyReplaceParagraph(tr, state.doc, state.schema, op);\n break;\n case 'insert_after':\n applyInsertAfter(tr, state.doc, state.schema, op);\n break;\n case 'insert_before':\n applyInsertBefore(tr, state.doc, state.schema, op);\n break;\n case 'delete':\n applyDelete(tr, state.doc, op);\n break;\n case 'replace_section':\n applyReplaceSection(tr, state.doc, state.schema, op);\n break;\n case 'add_comment':\n // Validate target exists; actual mark handling happens in applyAddCommentMarks\n applyAddCommentValidate(state.doc, op);\n break;\n case 'replace_cell':\n applyReplaceCell(tr, state.doc, state.schema, op);\n break;\n case 'insert_row':\n applyInsertRow(tr, state.doc, state.schema, op);\n break;\n case 'delete_row':\n applyDeleteRow(tr, state.doc, op);\n break;\n case 'insert_column':\n applyInsertColumn(tr, state.doc, state.schema, op);\n break;\n case 'delete_column':\n applyDeleteColumn(tr, state.doc, op);\n break;\n case 'insert_table':\n applyInsertTable(tr, state.doc, state.schema, op);\n break;\n case 'replace_table':\n applyReplaceTable(tr, state.doc, state.schema, op);\n break;\n default:\n // All 13 operation types covered; this handles any future additions\n (op as unknown as { status: string; error: string }).status = 'failed';\n (op as unknown as { status: string; error: string }).error = 'Unknown operation type';\n }\n if (op.status !== 'failed') {\n op.status = 'applied';\n }\n } catch (err) {\n op.status = 'failed';\n op.error = err instanceof Error ? err.message : String(err);\n }\n }\n\n editor.view.dispatch(tr);\n return operations;\n}\n\n// --- Paragraph Operations ---\n\nfunction applyReplaceText(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: ReplaceTextOp\n): void {\n const found = findTargetNode(doc, op.target, op as EditOperationWithStatus);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Node not found';\n return;\n }\n\n const { node, pos } = found;\n const textContent = node.textContent;\n const findIndex = textContent.indexOf(op.find);\n\n if (findIndex === -1) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = `Text \"${op.find}\" not found in node`;\n return;\n }\n\n // Calculate absolute positions, accounting for node start offset\n // +1 for the node opening token\n const contentStart = pos + 1;\n const from = contentStart + findIndex;\n const to = from + op.find.length;\n\n const replacement = parseInline(op.replace, schema);\n\n tr.replaceWith(\n tr.mapping.map(from),\n tr.mapping.map(to),\n replacement\n );\n}\n\nfunction applyReplaceParagraph(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: ReplaceParagraphOp\n): void {\n const found = findTargetNode(doc, op.target, op as EditOperationWithStatus);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Node not found';\n return;\n }\n\n const { node, pos } = found;\n\n // Block-type change: the model emits a different tag (`<h2>`, `<li>`) when it\n // wants the block type to switch. Compare parsed block's type against the\n // target's and either whole-node-replace or just swap inner content.\n const blocks = parseBlockHtml(op.content, schema);\n if (blocks.length === 1 && blocks[0].type !== node.type) {\n const newNode = injectSynkId(blocks[0], op.target);\n tr.replaceWith(\n tr.mapping.map(pos),\n tr.mapping.map(pos + node.nodeSize),\n newNode\n );\n return;\n }\n\n const contentStart = pos + 1;\n const contentEnd = pos + node.nodeSize - 1;\n const replacement = parseInline(op.content, schema);\n\n tr.replaceWith(\n tr.mapping.map(contentStart),\n tr.mapping.map(contentEnd),\n replacement\n );\n}\n\nfunction applyInsertAfter(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: InsertAfterOp\n): void {\n const found = findTargetNode(doc, op.target, op as EditOperationWithStatus);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Node not found';\n return;\n }\n\n const { node, pos } = found;\n const insertPos = pos + node.nodeSize;\n\n const newNode = createBlockNode(schema, op.new_id, op.content);\n tr.insert(tr.mapping.map(insertPos), newNode);\n}\n\nfunction applyInsertBefore(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: InsertBeforeOp\n): void {\n const found = findTargetNode(doc, op.target, op as EditOperationWithStatus);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Node not found';\n return;\n }\n\n const newNode = createBlockNode(schema, op.new_id, op.content);\n tr.insert(tr.mapping.map(found.pos), newNode);\n}\n\nfunction applyDelete(\n tr: Transaction,\n doc: ProseMirrorNode,\n op: DeleteOp\n): void {\n const found = findTargetNode(doc, op.target, op as EditOperationWithStatus);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Node not found';\n return;\n }\n\n const { node, pos } = found;\n tr.delete(tr.mapping.map(pos), tr.mapping.map(pos + node.nodeSize));\n}\n\nfunction applyReplaceSection(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: ReplaceSectionOp\n): void {\n // Parse the replacement content into nodes\n const newNodes = parseBlock(op.content, schema);\n if (newNodes.length === 0) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Empty replacement content';\n return;\n }\n\n // Find all nodes in the section by walking the doc and collecting nodes\n // that appear between section boundaries. For simplicity, replace based\n // on the first and last node IDs found in the content.\n // This is a simplified implementation — full section boundary detection\n // would require the section detector.\n const fragment = schema.nodes.doc\n ? undefined // fragments are created from arrays\n : undefined;\n\n // For now, insert new nodes and let the caller handle section boundaries\n // A full implementation would use detectSections to find boundaries\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'replace_section requires section boundary detection — use targeted operations instead';\n}\n\n// --- Table Operations ---\n\nfunction applyReplaceCell(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: ReplaceCellOp\n): void {\n const found = findNodeBySynkId(doc, op.target);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Cell not found';\n return;\n }\n\n const { node, pos } = found;\n const contentStart = pos + 1;\n const contentEnd = pos + node.nodeSize - 1;\n\n let contentNodes: ProseMirrorNode[];\n\n if (op.paragraphs) {\n // Complex cell: multiple paragraphs\n contentNodes = op.paragraphs.map((p) =>\n createParagraphNode(schema, p.id, p.content)\n );\n } else {\n // Simple cell: single paragraph\n const textNodes = parseInline(op.content || '', schema);\n const para = schema.nodes.paragraph.create(null, textNodes.length > 0 ? textNodes : undefined);\n contentNodes = [para];\n }\n\n tr.replaceWith(\n tr.mapping.map(contentStart),\n tr.mapping.map(contentEnd),\n contentNodes\n );\n}\n\nfunction applyInsertRow(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: InsertRowOp\n): void {\n const tableFound = findNodeBySynkId(doc, op.table);\n if (!tableFound) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Table not found';\n return;\n }\n\n const { node: tableNode, pos: tablePos } = tableFound;\n\n // Find the position after the target row\n let rowIndex = 0;\n let insertPos = tablePos + 1; // start after table opening\n\n tableNode.forEach((row, offset) => {\n if (row.type.name === 'tableRow') {\n if (rowIndex <= op.after_row) {\n insertPos = tablePos + 1 + offset + row.nodeSize;\n }\n rowIndex++;\n }\n });\n\n // Create the new row\n const cells = op.cells.map((cell) => {\n const textNodes = parseInline(cell.content, schema);\n const para = schema.nodes.paragraph.create(null, textNodes.length > 0 ? textNodes : undefined);\n return schema.nodes.tableCell.create(\n { [NODE_ID_ATTR]: cell.id },\n para\n );\n });\n\n const newRow = schema.nodes.tableRow.create(null, cells);\n tr.insert(tr.mapping.map(insertPos), newRow);\n}\n\nfunction applyDeleteRow(\n tr: Transaction,\n doc: ProseMirrorNode,\n op: DeleteRowOp\n): void {\n const tableFound = findNodeBySynkId(doc, op.table);\n if (!tableFound) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Table not found';\n return;\n }\n\n const { node: tableNode, pos: tablePos } = tableFound;\n\n let rowIndex = 0;\n tableNode.forEach((row, offset) => {\n if (row.type.name === 'tableRow' && rowIndex === op.row) {\n const rowPos = tablePos + 1 + offset;\n tr.delete(tr.mapping.map(rowPos), tr.mapping.map(rowPos + row.nodeSize));\n }\n if (row.type.name === 'tableRow') rowIndex++;\n });\n}\n\nfunction applyInsertColumn(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: InsertColumnOp\n): void {\n const tableFound = findNodeBySynkId(doc, op.table);\n if (!tableFound) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Table not found';\n return;\n }\n\n const { node: tableNode, pos: tablePos } = tableFound;\n\n let dataRowIndex = 0;\n\n tableNode.forEach((row, rowOffset) => {\n if (row.type.name !== 'tableRow') return;\n\n const isHeaderRow = row.child(0)?.type.name === 'tableHeader';\n\n // Find insert position within the row: after the after_column cell\n let cellIndex = 0;\n let cellInsertPos = tablePos + 1 + rowOffset + 1; // row start\n\n row.forEach((cell, cellOffset) => {\n if (cellIndex <= op.after_column) {\n cellInsertPos = tablePos + 1 + rowOffset + 1 + cellOffset + cell.nodeSize;\n }\n cellIndex++;\n });\n\n // Determine cell content and ID\n let cellData: { id: string; content: string };\n if (isHeaderRow) {\n cellData = op.header;\n } else {\n cellData = op.cells[dataRowIndex] || { id: '', content: '' };\n dataRowIndex++;\n }\n\n const textNodes = parseInline(cellData.content, schema);\n const para = schema.nodes.paragraph.create(null, textNodes.length > 0 ? textNodes : undefined);\n\n const cellType = isHeaderRow ? schema.nodes.tableHeader : schema.nodes.tableCell;\n const newCell = cellType.create(\n { [NODE_ID_ATTR]: cellData.id },\n para\n );\n\n tr.insert(tr.mapping.map(cellInsertPos), newCell);\n });\n}\n\nfunction applyDeleteColumn(\n tr: Transaction,\n doc: ProseMirrorNode,\n op: DeleteColumnOp\n): void {\n const tableFound = findNodeBySynkId(doc, op.table);\n if (!tableFound) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Table not found';\n return;\n }\n\n const { node: tableNode, pos: tablePos } = tableFound;\n\n // Delete cells in reverse row order to avoid position shifts\n const deletions: { from: number; to: number }[] = [];\n\n tableNode.forEach((row, rowOffset) => {\n if (row.type.name !== 'tableRow') return;\n\n let cellIndex = 0;\n row.forEach((cell, cellOffset) => {\n if (cellIndex === op.column) {\n const cellPos = tablePos + 1 + rowOffset + 1 + cellOffset;\n deletions.push({ from: cellPos, to: cellPos + cell.nodeSize });\n }\n cellIndex++;\n });\n });\n\n // Apply deletions in reverse order\n for (let i = deletions.length - 1; i >= 0; i--) {\n const { from, to } = deletions[i];\n tr.delete(tr.mapping.map(from), tr.mapping.map(to));\n }\n}\n\nfunction applyInsertTable(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: InsertTableOp\n): void {\n const afterFound = findNodeBySynkId(doc, op.after);\n if (!afterFound) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Target node not found';\n return;\n }\n\n const insertPos = afterFound.pos + afterFound.node.nodeSize;\n const tableNode = buildTableNode(schema, op.table_id, op.headers, op.rows);\n tr.insert(tr.mapping.map(insertPos), tableNode);\n}\n\nfunction applyReplaceTable(\n tr: Transaction,\n doc: ProseMirrorNode,\n schema: Schema,\n op: ReplaceTableOp\n): void {\n const found = findNodeBySynkId(doc, op.target);\n if (!found) {\n (op as EditOperationWithStatus).status = 'failed';\n (op as EditOperationWithStatus).error = 'Table not found';\n return;\n }\n\n const { node, pos } = found;\n const tableNode = buildTableNode(schema, op.target, op.headers, op.rows);\n tr.replaceWith(\n tr.mapping.map(pos),\n tr.mapping.map(pos + node.nodeSize),\n tableNode\n );\n}\n\n// --- Helpers ---\n\n/**\n * Create the appropriate block node (heading, list item, or paragraph) based\n * on markdown prefixes in the content string. Falls back to a plain paragraph\n * when no block-level marker is detected.\n */\nfunction createBlockNode(\n schema: Schema,\n synkId: string,\n content: string\n): ProseMirrorNode {\n // Parse as a block fragment. If exactly one block returned, that's the new\n // node (with synkId injected). Otherwise wrap inline content in a paragraph\n // so we always produce *something*.\n const blocks = parseBlockHtml(content, schema);\n if (blocks.length === 1) {\n return injectSynkId(blocks[0], synkId);\n }\n const textNodes = parseInlineHtml(content, schema);\n return schema.nodes.paragraph.create(\n { [NODE_ID_ATTR]: synkId },\n textNodes.length > 0 ? textNodes : undefined,\n );\n}\n\n/** Simple paragraph node — used by table cell helpers where block detection is unwanted. */\nfunction createParagraphNode(\n schema: Schema,\n synkId: string,\n content: string\n): ProseMirrorNode {\n const textNodes = parseInline(content, schema);\n return schema.nodes.paragraph.create(\n { [NODE_ID_ATTR]: synkId },\n textNodes.length > 0 ? textNodes : undefined\n );\n}\n\nfunction buildTableNode(\n schema: Schema,\n tableId: string,\n headers: { id: string; content: string }[],\n rows: { id: string; content: string }[][]\n): ProseMirrorNode {\n const allRows: ProseMirrorNode[] = [];\n\n // Header row\n if (headers.length > 0) {\n const headerCells = headers.map((h) => {\n const textNodes = parseInline(h.content, schema);\n const para = schema.nodes.paragraph.create(null, textNodes.length > 0 ? textNodes : undefined);\n return schema.nodes.tableHeader.create(\n { [NODE_ID_ATTR]: h.id },\n para\n );\n });\n allRows.push(schema.nodes.tableRow.create(null, headerCells));\n }\n\n // Data rows\n for (const row of rows) {\n const cells = row.map((cell) => {\n const textNodes = parseInline(cell.content, schema);\n const para = schema.nodes.paragraph.create(null, textNodes.length > 0 ? textNodes : undefined);\n return schema.nodes.tableCell.create(\n { [NODE_ID_ATTR]: cell.id },\n para\n );\n });\n allRows.push(schema.nodes.tableRow.create(null, cells));\n }\n\n return schema.nodes.table.create(\n { [NODE_ID_ATTR]: tableId },\n allRows\n );\n}\n\n/**\n * Apply a single operation as its own ProseMirror transaction (separate undo step).\n * Returns the operation with updated status.\n */\nexport function applySingleOp(\n editor: Editor,\n operation: EditOperationWithStatus\n): EditOperationWithStatus {\n const { state } = editor;\n const tr = state.tr;\n const op = { ...operation };\n\n try {\n switch (op.type) {\n case 'replace_text':\n applyReplaceText(tr, state.doc, state.schema, op);\n break;\n case 'replace_paragraph':\n applyReplaceParagraph(tr, state.doc, state.schema, op);\n break;\n case 'insert_after':\n applyInsertAfter(tr, state.doc, state.schema, op);\n break;\n case 'insert_before':\n applyInsertBefore(tr, state.doc, state.schema, op);\n break;\n case 'delete':\n applyDelete(tr, state.doc, op);\n break;\n case 'replace_section':\n applyReplaceSection(tr, state.doc, state.schema, op);\n break;\n case 'add_comment':\n applyAddCommentValidate(state.doc, op);\n break;\n case 'replace_cell':\n applyReplaceCell(tr, state.doc, state.schema, op);\n break;\n case 'insert_row':\n applyInsertRow(tr, state.doc, state.schema, op);\n break;\n case 'delete_row':\n applyDeleteRow(tr, state.doc, op);\n break;\n case 'insert_column':\n applyInsertColumn(tr, state.doc, state.schema, op);\n break;\n case 'delete_column':\n applyDeleteColumn(tr, state.doc, op);\n break;\n case 'insert_table':\n applyInsertTable(tr, state.doc, state.schema, op);\n break;\n case 'replace_table':\n applyReplaceTable(tr, state.doc, state.schema, op);\n break;\n default:\n (op as unknown as { status: string; error: string }).status = 'failed';\n (op as unknown as { status: string; error: string }).error = 'Unknown operation type';\n }\n if (op.status !== 'failed') {\n op.status = 'applied';\n }\n } catch (err) {\n op.status = 'failed';\n op.error = err instanceof Error ? err.message : String(err);\n }\n\n editor.view.dispatch(tr);\n return op;\n}\n\n/**\n * Get the text content of a node by its synkId.\n * Returns empty string if not found.\n */\nexport function getNodeTextBySynkId(editor: Editor, synkId: string): string {\n const found = findNodeBySynkId(editor.state.doc, synkId);\n if (!found) return '';\n return found.node.textContent;\n}\n\n/**\n * After edits are applied, add inline comment marks on affected nodes\n * with the LLM's reasoning text. Dispatches a separate transaction so\n * the comments form their own undo step.\n *\n * Returns Comment objects ready to merge into the comments state.\n */\nexport function addReasoningComments(\n editor: Editor,\n operations: EditOperationWithStatus[]\n): Comment[] {\n const { state } = editor;\n const tr = state.tr;\n const commentMarkType = state.schema.marks.inlineComment;\n if (!commentMarkType) return [];\n\n const comments: Comment[] = [];\n\n for (const op of operations) {\n if (op.status !== 'applied' || !op.reasoning) continue;\n\n const synkId = getCommentTargetId(op);\n if (!synkId) continue;\n\n const found = findNodeBySynkId(state.doc, synkId);\n if (!found) continue;\n\n const { node, pos } = found;\n const textContent = node.textContent;\n if (!textContent) continue;\n\n // Mark the full text content of the affected node\n const from = pos + 1;\n const to = pos + node.nodeSize - 1;\n if (from >= to) continue;\n\n const commentId = crypto.randomUUID();\n\n tr.addMark(from, to, commentMarkType.create({ commentId, severity: 'low', resolved: true, isAI: true }));\n\n comments.push({\n id: commentId,\n author: { username: 'AI', isAI: true },\n text: op.reasoning,\n replies: [],\n resolved: true,\n severity: 'low',\n createdAt: new Date().toISOString(),\n from,\n to,\n selectedText: textContent,\n });\n }\n\n if (comments.length > 0) {\n editor.view.dispatch(tr);\n }\n\n return comments;\n}\n\n/**\n * Validate that the target node exists for an add_comment operation.\n * The actual mark handling is deferred to applyAddCommentMarks.\n */\nfunction applyAddCommentValidate(\n doc: ProseMirrorNode,\n op: AddCommentOp & { status?: string; error?: string }\n): void {\n const found = findNodeBySynkId(doc, op.target);\n if (!found) {\n op.status = 'failed';\n op.error = 'Node not found';\n }\n}\n\n/**\n * Process all applied add_comment operations: resolve existing comments on\n * target nodes and attach new inline comment marks.\n *\n * Dispatches a separate ProseMirror transaction (like addReasoningComments).\n * Returns new Comment objects to merge into state and IDs of resolved comments.\n */\nexport function applyAddCommentMarks(\n editor: Editor,\n operations: EditOperationWithStatus[],\n options?: { skipResolve?: boolean }\n): { newComments: Comment[]; resolvedCommentIds: string[] } {\n const { state } = editor;\n const tr = state.tr;\n const commentMarkType = state.schema.marks.inlineComment;\n if (!commentMarkType) return { newComments: [], resolvedCommentIds: [] };\n\n const newComments: Comment[] = [];\n const resolvedCommentIds: string[] = [];\n\n for (const op of operations) {\n if (op.type !== 'add_comment' || op.status !== 'applied') continue;\n\n const found = findNodeBySynkId(state.doc, op.target);\n if (!found) continue;\n\n const { node, pos } = found;\n const textContent = node.textContent;\n if (!textContent) continue;\n\n const from = pos + 1;\n const to = pos + node.nodeSize - 1;\n if (from >= to) continue;\n\n // Clean up stale AI reasoning marks (already resolved) on this node.\n // Never touch unresolved marks — those are user-added open comments.\n if (!options?.skipResolve) {\n node.descendants((child, childPos) => {\n if (!child.isText) return;\n for (const mark of child.marks) {\n if (mark.type.name === 'inlineComment' && mark.attrs.commentId && mark.attrs.resolved) {\n const absFrom = pos + 1 + childPos;\n const absTo = absFrom + child.nodeSize;\n tr.removeMark(absFrom, absTo, mark);\n if (!resolvedCommentIds.includes(mark.attrs.commentId)) {\n resolvedCommentIds.push(mark.attrs.commentId);\n }\n }\n }\n });\n }\n\n // Map API severity to our type (default to 'moderate')\n const severity = (op.comment_severity === 'high' || op.comment_severity === 'low')\n ? op.comment_severity\n : 'moderate' as const;\n\n // Add the new comment mark\n const commentId = crypto.randomUUID();\n const resolved = !options?.skipResolve;\n tr.addMark(from, to, commentMarkType.create({ commentId, severity, resolved, isAI: true }));\n\n newComments.push({\n id: commentId,\n author: { username: op.comment_author, isAI: true },\n text: op.comment_text,\n replies: [],\n resolved,\n severity,\n createdAt: new Date().toISOString(),\n from,\n to,\n selectedText: textContent,\n });\n }\n\n if (newComments.length > 0 || resolvedCommentIds.length > 0) {\n editor.view.dispatch(tr);\n }\n\n return { newComments, resolvedCommentIds };\n}\n\n/** Determine which node to attach the reasoning comment to. */\nfunction getCommentTargetId(op: EditOperationWithStatus): string | null {\n switch (op.type) {\n case 'replace_text':\n case 'replace_paragraph':\n case 'replace_cell':\n return op.target;\n case 'insert_after':\n case 'insert_before':\n return op.new_id;\n // add_comment has its own comment handling; delete / table-structural ops have no content to comment on\n case 'add_comment':\n default:\n return null;\n }\n}\n\n/**\n * Generate a string key for an applied operation (used in confirm request).\n */\nexport function operationKey(op: EditOperationWithStatus): string {\n switch (op.type) {\n case 'replace_text':\n case 'replace_paragraph':\n case 'delete':\n case 'replace_cell':\n case 'replace_section':\n case 'add_comment':\n return `${op.type}:${op.target}`;\n case 'insert_after':\n return `${op.type}:${op.new_id}`;\n case 'insert_before':\n return `${op.type}:${op.new_id}`;\n case 'insert_row':\n return `${op.type}:${op.table}:row${op.after_row + 1}`;\n case 'delete_row':\n return `${op.type}:${op.table}:row${op.row}`;\n case 'insert_column':\n return `${op.type}:${op.table}:col${op.after_column + 1}`;\n case 'delete_column':\n return `${op.type}:${op.table}:col${op.column}`;\n case 'insert_table':\n return `${op.type}:${op.table_id}`;\n case 'replace_table':\n return `${op.type}:${op.target}`;\n default:\n return `unknown`;\n }\n}\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport { NODE_ID_ATTR } from './nodeIdUtils';\n\nexport interface DocumentSection {\n /** Section identifier, e.g. 'synk-section-0' for preamble, 'synk-section-1' etc. */\n id: string;\n /** Heading text, 'Preamble', or 'Full Document' */\n title: string;\n /** Heading level (0 for preamble, 1-6 for headings) */\n level: number;\n /** ProseMirror position of the first node in this section */\n startPos: number;\n /** ProseMirror position of the end of the last node in this section */\n endPos: number;\n /** synkId of the heading node, null for preamble */\n headingSynkId: string | null;\n /** Parent section ID for hierarchy, null for top-level */\n parentId: string | null;\n}\n\n/**\n * Detect sections in the document by walking top-level nodes for headings.\n *\n * Rules (from ADR-014):\n * 1. Every heading node starts a new section.\n * 2. Content before the first heading is the preamble (synk-section-0, level 0).\n * 3. No headings at all → single section (synk-section-1, \"Full Document\").\n * 4. Hierarchy: heading level N is a child of the nearest preceding heading with level < N.\n */\nexport function detectSections(doc: ProseMirrorNode): DocumentSection[] {\n const sections: DocumentSection[] = [];\n\n // Collect top-level nodes with their positions\n const topLevelNodes: { node: ProseMirrorNode; pos: number }[] = [];\n doc.forEach((node, offset) => {\n topLevelNodes.push({ node, pos: offset + 1 });\n });\n\n if (topLevelNodes.length === 0) return [];\n\n let sectionCounter = 0;\n let currentSection: DocumentSection | null = null;\n\n for (const { node, pos } of topLevelNodes) {\n if (node.type.name === 'heading') {\n // Close the current section\n if (currentSection) {\n currentSection.endPos = pos;\n sections.push(currentSection);\n }\n\n sectionCounter++;\n currentSection = {\n id: `synk-section-${sectionCounter}`,\n title: node.textContent || `Section ${sectionCounter}`,\n level: node.attrs.level || 1,\n startPos: pos,\n endPos: 0,\n headingSynkId: node.attrs[NODE_ID_ATTR] || null,\n parentId: null,\n };\n } else {\n if (!currentSection && sectionCounter === 0) {\n // Preamble: content before the first heading\n currentSection = {\n id: 'synk-section-0',\n title: 'Preamble',\n level: 0,\n startPos: pos,\n endPos: 0,\n headingSynkId: null,\n parentId: null,\n };\n }\n }\n }\n\n // Close the last section\n if (currentSection) {\n currentSection.endPos = doc.content.size;\n sections.push(currentSection);\n }\n\n // Special case: no headings at all → single \"Full Document\" section\n if (sections.length === 0) {\n sections.push({\n id: 'synk-section-1',\n title: 'Full Document',\n level: 1,\n startPos: 1,\n endPos: doc.content.size,\n headingSynkId: null,\n parentId: null,\n });\n return sections;\n }\n\n // If only preamble (no headings), no hierarchy to build\n if (sections.length === 1 && sections[0].id === 'synk-section-0') {\n return sections;\n }\n\n return buildHierarchy(sections);\n}\n\n/**\n * Assign parentId to each section based on heading levels.\n * A heading with level N is a child of the nearest preceding heading with level < N.\n */\nfunction buildHierarchy(sections: DocumentSection[]): DocumentSection[] {\n // Stack tracks the current ancestor chain\n const stack: DocumentSection[] = [];\n\n for (const section of sections) {\n // Preamble is always top-level\n if (section.level === 0) {\n section.parentId = null;\n stack.length = 0;\n stack.push(section);\n continue;\n }\n\n // Pop stack until we find a section with level < current\n while (stack.length > 0 && stack[stack.length - 1].level >= section.level) {\n stack.pop();\n }\n\n if (stack.length > 0) {\n section.parentId = stack[stack.length - 1].id;\n } else {\n section.parentId = null;\n }\n\n stack.push(section);\n }\n\n return sections;\n}\n\n/**\n * Get a section by its ID.\n */\nexport function findSectionById(\n sections: DocumentSection[],\n sectionId: string\n): DocumentSection | undefined {\n return sections.find((s) => s.id === sectionId);\n}\n\n/**\n * Get child sections of a given parent.\n */\nexport function getChildSections(\n sections: DocumentSection[],\n parentId: string\n): DocumentSection[] {\n return sections.filter((s) => s.parentId === parentId);\n}\n","import type { Node as ProseMirrorNode } from '@tiptap/pm/model';\n\n/**\n * Metadata about the document's dominant styles.\n * Surfaced to the agent via the `read_document_styles` tool so generated\n * content can match the doc's prevailing font + alignment.\n */\nexport interface DocumentStyles {\n fontFamily: string | null;\n textAlign: string | null;\n}\n\n/**\n * Collect dominant document styles from the first few paragraphs.\n */\nexport function collectDocumentStyles(doc: ProseMirrorNode): DocumentStyles {\n const styles: DocumentStyles = {\n fontFamily: null,\n textAlign: null,\n };\n\n let sampled = 0;\n const fontCounts: Record<string, number> = {};\n const alignCounts: Record<string, number> = {};\n\n doc.descendants((node) => {\n if (sampled >= 10) return false;\n if (node.type.name === 'paragraph' || node.type.name === 'heading') {\n sampled++;\n\n node.forEach((child) => {\n if (child.isText) {\n const fontMark = child.marks.find((m) => m.type.name === 'textStyle');\n if (fontMark?.attrs.fontFamily) {\n const font = fontMark.attrs.fontFamily;\n fontCounts[font] = (fontCounts[font] || 0) + 1;\n }\n }\n });\n\n const align = node.attrs.textAlign;\n if (align) {\n alignCounts[align] = (alignCounts[align] || 0) + 1;\n }\n }\n });\n\n const topFont = Object.entries(fontCounts).sort((a, b) => b[1] - a[1])[0];\n const topAlign = Object.entries(alignCounts).sort((a, b) => b[1] - a[1])[0];\n\n if (topFont) styles.fontFamily = topFont[0];\n if (topAlign) styles.textAlign = topAlign[0];\n\n return styles;\n}\n","/**\n * HTML serializer for the editor agent.\n *\n * Replaces the ID-annotated markdown serializer in `utils/contentSerializer.ts`\n * for the agent path. Emits ID-annotated HTML — every block carries\n * `data-synk-id=\"p:7a3f\"` (or `t:`, `c:`) and inline formatting uses standard\n * HTML elements that the model is already fluent in.\n *\n * Why HTML, see: `docs/superpowers/specs/2026-05-15-editor-html-representation.md`\n *\n * The output is filtered to a tight allowlist so token cost stays within\n * ~2-3× the markdown baseline. Suggestion-mode marks (insertion / deletion /\n * modification) and inline-comment marks are unwrapped here — the agent\n * receives suggestion + comment state separately via the annotations payload,\n * so these wrappers would only be noise.\n */\n\nimport { DOMSerializer, type Node as PMNode } from '@tiptap/pm/model';\n\nimport { NODE_ID_ATTR } from '../utils/nodeIdUtils';\nimport type { DocumentSection } from '../utils/sectionDetector';\n\n/**\n * Style properties retained in `style=\"…\"` attributes. Everything else is\n * stripped (TipTap rendering may emit decorative styles we don't want the\n * model to see or echo back).\n */\nconst KEEP_STYLE_PROPS = new Set([\n 'text-align',\n 'color',\n 'font-family',\n 'background-color',\n]);\n\n/**\n * `data-*` attributes retained regardless of element. Indent's data-indent\n * is schema-meaningful (the extension parses it back). data-synk-id is the\n * agent's node addressing. data-section is the existing business identifier.\n */\nconst KEEP_DATA_ATTRS = new Set(['data-synk-id', 'data-indent', 'data-section']);\n\n/**\n * Per-tag attribute allowlist (in addition to the global data-* allowlist).\n */\nconst TAG_ATTR_ALLOWLIST: Record<string, ReadonlySet<string>> = {\n a: new Set(['href']),\n td: new Set(['colspan', 'rowspan']),\n th: new Set(['colspan', 'rowspan', 'scope']),\n code: new Set(['class']), // class filtered to `language-*` only by sanitizeElement\n};\n\n/**\n * Serialize a single section's contents to ID-annotated HTML, skipping the\n * section's own heading (mirrors `serializeSection` in contentSerializer.ts).\n */\nexport function serializeSection(doc: PMNode, section: DocumentSection): string {\n const serializer = DOMSerializer.fromSchema(doc.type.schema);\n const container = document.createElement('div');\n\n doc.nodesBetween(section.startPos, section.endPos, (node, pos) => {\n if (node.type.name === 'doc') return true;\n const parent = doc.resolve(pos).parent;\n if (parent.type.name !== 'doc') return false;\n\n // Skip the section's own heading (it's already in section.title metadata).\n if (\n node.type.name === 'heading' &&\n section.headingSynkId !== null &&\n node.attrs[NODE_ID_ATTR] === section.headingSynkId\n ) {\n return false;\n }\n\n const dom = serializer.serializeNode(node);\n container.appendChild(dom);\n return false; // top-level only; serializeNode handles children\n });\n\n cleanTree(container);\n return container.innerHTML;\n}\n\n/**\n * Serialize an arbitrary [from, to] range. Used by the round-trip test harness\n * and any future caller that wants a non-section slice.\n */\nexport function serializeRange(doc: PMNode, from: number, to: number): string {\n const slice = doc.slice(from, to);\n const serializer = DOMSerializer.fromSchema(doc.type.schema);\n const container = document.createElement('div');\n container.appendChild(serializer.serializeFragment(slice.content));\n cleanTree(container);\n return container.innerHTML;\n}\n\n/**\n * Serialize the entire document to ID-annotated HTML. Used by the round-trip\n * test harness and by callers that want the whole doc (not section-scoped).\n */\nexport function serializeDoc(doc: PMNode): string {\n return serializeRange(doc, 0, doc.content.size);\n}\n\n/**\n * Serialize just the inline content of a single block node (no outer wrapper).\n * Used by inverseOps when capturing cell contents for revert — the captured\n * string is later fed back into `applySingleOp` via the same HTML parser, so\n * the round-trip is the same primitive used everywhere else.\n */\nexport function serializeInlineHtml(node: PMNode): string {\n const serializer = DOMSerializer.fromSchema(node.type.schema);\n const fragment = serializer.serializeFragment(node.content);\n const container = document.createElement('div');\n container.appendChild(fragment);\n cleanTree(container);\n return container.innerHTML;\n}\n\n/**\n * Strip non-schema-meaningful attrs, unwrap suggestion/comment marks, drop\n * decorative whitespace. The output is a compact HTML string.\n */\nfunction cleanTree(root: Element): void {\n unwrapSuggestionMarks(root);\n sanitizeAttributes(root);\n collapseDecorativeWhitespace(root);\n}\n\n/**\n * Suggestion-mode and inline-comment marks are editor chrome. The agent reads\n * suggestion + comment state from the annotations payload returned alongside\n * the content. Unwrapping here keeps the underlying doc text intact while\n * removing the visualisation wrapper.\n */\nfunction unwrapSuggestionMarks(root: Element): void {\n const toUnwrap: Element[] = [];\n\n function walk(node: Element): void {\n for (const child of Array.from(node.children)) walk(child);\n if (shouldUnwrap(node)) toUnwrap.push(node);\n }\n walk(root);\n\n for (const el of toUnwrap) unwrap(el);\n}\n\nfunction shouldUnwrap(el: Element): boolean {\n const tag = el.tagName.toLowerCase();\n if (tag === 'ins' || tag === 'del') return true;\n if (tag === 'span' && el.getAttribute('data-type') === 'modification') return true;\n if (tag === 'span' && el.hasAttribute('data-comment-id')) return true;\n return false;\n}\n\nfunction unwrap(el: Element): void {\n const parent = el.parentNode;\n if (!parent) return;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n}\n\nfunction sanitizeAttributes(root: Element): void {\n for (const el of Array.from(root.querySelectorAll('*'))) {\n sanitizeElement(el);\n }\n}\n\nfunction sanitizeElement(el: Element): void {\n const tag = el.tagName.toLowerCase();\n const tagAllowlist = TAG_ATTR_ALLOWLIST[tag];\n\n const toRemove: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n const name = attr.name.toLowerCase();\n if (KEEP_DATA_ATTRS.has(name)) continue;\n if (name === 'style' || name === 'class') continue; // handled below\n if (tagAllowlist?.has(name)) continue;\n toRemove.push(attr.name);\n }\n for (const name of toRemove) el.removeAttribute(name);\n\n const style = el.getAttribute('style');\n if (style !== null) {\n const filtered = filterStyle(style);\n if (filtered) el.setAttribute('style', filtered);\n else el.removeAttribute('style');\n }\n\n const cls = el.getAttribute('class');\n if (cls !== null) {\n if (tag === 'code') {\n const langClass = cls\n .split(/\\s+/)\n .find((c) => c.startsWith('language-'));\n if (langClass) el.setAttribute('class', langClass);\n else el.removeAttribute('class');\n } else {\n el.removeAttribute('class');\n }\n }\n}\n\nfunction filterStyle(style: string): string {\n const kept: string[] = [];\n for (const prop of style.split(';')) {\n const trimmed = prop.trim();\n if (!trimmed) continue;\n const colon = trimmed.indexOf(':');\n if (colon < 0) continue;\n const name = trimmed.slice(0, colon).trim().toLowerCase();\n const value = trimmed.slice(colon + 1).trim();\n if (KEEP_STYLE_PROPS.has(name)) {\n kept.push(`${name}:${value}`);\n }\n // margin-left is dropped — indent extension also emits data-indent which\n // we keep, so the schema attr is preserved either way.\n }\n return kept.join(';');\n}\n\n/**\n * Remove text nodes that consist only of whitespace and sit between block-level\n * children of a block container (e.g. the newlines TipTap's renderer inserts\n * between `<tr>` elements). Decorative; not part of the doc.\n */\nfunction collapseDecorativeWhitespace(root: Element): void {\n const blockContainers = new Set([\n 'div',\n 'ul',\n 'ol',\n 'table',\n 'thead',\n 'tbody',\n 'tr',\n 'blockquote',\n ]);\n\n const walker = root.ownerDocument!.createTreeWalker(\n root,\n NodeFilter.SHOW_TEXT,\n );\n const toRemove: Node[] = [];\n let node: Node | null;\n while ((node = walker.nextNode())) {\n if (!node.nodeValue || !/^\\s*$/.test(node.nodeValue)) continue;\n const parent = node.parentNode as Element | null;\n if (!parent) continue;\n if (blockContainers.has(parent.tagName.toLowerCase())) {\n toRemove.push(node);\n }\n }\n for (const n of toRemove) n.parentNode?.removeChild(n);\n}\n","/**\n * Serializes comments and suggestions into structured annotation payloads\n * for the AI editing pipeline, mapping ProseMirror positions to synkIds.\n */\n\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport type { Comment, Suggestion } from '../types';\nimport { NODE_ID_ATTR, resolvePositionToSynkId } from './nodeIdUtils';\n\nexport interface CommentAnnotation {\n id: string;\n author: string;\n text: string;\n replies: Array<{ author: string; text: string }>;\n resolved: boolean;\n targetSynkId: string;\n selectedText: string;\n}\n\nexport interface SuggestionAnnotation {\n id: string;\n type: 'insertion' | 'deletion';\n author: string;\n text: string;\n targetSynkId: string;\n reason?: string;\n}\n\nexport interface DocumentAnnotations {\n comments: CommentAnnotation[];\n suggestions: SuggestionAnnotation[];\n}\n\n/**\n * Build the annotations payload from current comments and suggestions,\n * resolving their ProseMirror positions to paragraph synkIds.\n */\nexport function buildAnnotationsPayload(\n doc: ProseMirrorNode,\n comments: Comment[],\n suggestions: Suggestion[]\n): DocumentAnnotations {\n const commentAnnotations: CommentAnnotation[] = [];\n for (const c of comments) {\n if (c.resolved) continue;\n const targetSynkId = resolvePositionToSynkId(doc, c.from);\n if (!targetSynkId) continue;\n\n commentAnnotations.push({\n id: c.id,\n author: c.author.username,\n text: c.text,\n replies: c.replies.map((r) => ({\n author: r.author.username,\n text: r.text,\n })),\n resolved: c.resolved,\n targetSynkId,\n selectedText: c.selectedText,\n });\n }\n\n const suggestionAnnotations: SuggestionAnnotation[] = [];\n for (const s of suggestions) {\n const targetSynkId = resolvePositionToSynkId(doc, s.from);\n if (!targetSynkId) continue;\n\n suggestionAnnotations.push({\n id: s.id,\n type: s.type,\n author: s.author.username,\n text: s.text,\n targetSynkId,\n reason: s.data?.reason as string | undefined,\n });\n }\n\n return { comments: commentAnnotations, suggestions: suggestionAnnotations };\n}\n\n/**\n * Collect every synkId borne by a node whose position falls within [from, to].\n * Used by the agent's read_section tool to filter the document-wide annotations\n * payload down to just the comments/suggestions anchored inside the requested\n * section's range.\n */\nexport function collectSynkIdsInRange(\n doc: ProseMirrorNode,\n from: number,\n to: number\n): Set<string> {\n const ids = new Set<string>();\n doc.nodesBetween(from, to, (node) => {\n const id = node.attrs?.[NODE_ID_ATTR];\n if (typeof id === 'string') ids.add(id);\n });\n return ids;\n}\n","/**\n * Suggestion-mode id tracking — see spec §8.2.\n *\n * Each agent edit dispatch is rewritten by `withSuggestChanges` into\n * insertion / deletion / modification marks bearing a stable numeric `id`.\n * We snapshot the set of ids before and after a dispatch, then diff to\n * learn which ids the tool created.\n */\n\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\n\nconst TRACKED_MARK_NAMES = new Set<string>(['insertion', 'deletion', 'modification']);\n\nexport function collectSuggestionIds(doc: ProseMirrorNode): Set<number> {\n const ids = new Set<number>();\n doc.descendants((node) => {\n for (const mark of node.marks) {\n if (TRACKED_MARK_NAMES.has(mark.type.name)) {\n const id = mark.attrs.id;\n if (typeof id === 'number') ids.add(id);\n }\n }\n });\n return ids;\n}\n\nexport function diffSuggestionIds(before: Set<number>, after: Set<number>): number[] {\n const added: number[] = [];\n for (const id of after) {\n if (!before.has(id)) added.push(id);\n }\n return added;\n}\n","/**\n * Inverse-op capture for structural table ops that bypass suggestion mode.\n * See spec §8.8.\n *\n * Content ops (replace_text, insert_after, etc.) are revertible via\n * suggestion-mode rejection and do not need an inverse — only the six ops\n * below need one.\n */\n\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport type {\n EditOperation,\n InsertRowOp,\n DeleteRowOp,\n InsertColumnOp,\n DeleteColumnOp,\n InsertTableOp,\n ReplaceTableOp,\n} from '../types/editOperations';\nimport { findNodeBySynkId, NODE_ID_ATTR } from '../utils/nodeIdUtils';\nimport { serializeInlineHtml } from './htmlSerializer';\n\nconst REVERT_REASONING = 'agent revert';\n\n/**\n * Compute the inverse of a structural op, evaluated against `docBefore`\n * (the doc state immediately prior to applying `op`). Returns null when\n * the inverse cannot be derived — callers fall back to recording the\n * change without revert capability.\n */\nexport function computeInverse(\n op: EditOperation,\n docBefore: ProseMirrorNode,\n): EditOperation | null {\n switch (op.type) {\n case 'insert_row':\n return inverseInsertRow(op);\n case 'delete_row':\n return inverseDeleteRow(op, docBefore);\n case 'insert_column':\n return inverseInsertColumn(op);\n case 'delete_column':\n return inverseDeleteColumn(op, docBefore);\n case 'insert_table':\n return inverseInsertTable(op);\n case 'replace_table':\n return inverseReplaceTable(op, docBefore);\n default:\n return null;\n }\n}\n\nfunction inverseInsertRow(op: InsertRowOp): EditOperation {\n return {\n type: 'delete_row',\n table: op.table,\n row: op.after_row + 1,\n reasoning: REVERT_REASONING,\n };\n}\n\nfunction inverseDeleteRow(op: DeleteRowOp, docBefore: ProseMirrorNode): EditOperation | null {\n const tableFound = findNodeBySynkId(docBefore, op.table);\n if (!tableFound) return null;\n\n const rowNode = nthTableRow(tableFound.node, op.row);\n if (!rowNode) return null;\n\n const cells: { id: string; content: string }[] = [];\n rowNode.forEach((cell) => {\n const id = (cell.attrs[NODE_ID_ATTR] as string | undefined) ?? '';\n cells.push({ id, content: serializeCellInline(cell) });\n });\n\n return {\n type: 'insert_row',\n table: op.table,\n after_row: op.row - 1,\n cells,\n reasoning: REVERT_REASONING,\n };\n}\n\nfunction inverseInsertColumn(op: InsertColumnOp): EditOperation {\n return {\n type: 'delete_column',\n table: op.table,\n column: op.after_column + 1,\n reasoning: REVERT_REASONING,\n };\n}\n\nfunction inverseDeleteColumn(op: DeleteColumnOp, docBefore: ProseMirrorNode): EditOperation | null {\n const tableFound = findNodeBySynkId(docBefore, op.table);\n if (!tableFound) return null;\n\n let header: { id: string; content: string } | null = null;\n const cells: { id: string; content: string }[] = [];\n\n tableFound.node.forEach((row) => {\n if (row.type.name !== 'tableRow') return;\n const cell = nthCell(row, op.column);\n if (!cell) return;\n const id = (cell.attrs[NODE_ID_ATTR] as string | undefined) ?? '';\n const entry = { id, content: serializeCellInline(cell) };\n if (cell.type.name === 'tableHeader') {\n header = entry;\n } else {\n cells.push(entry);\n }\n });\n\n // insert_column requires a header even for header-less tables; synthesize one if needed\n const safeHeader = header ?? { id: '', content: '' };\n\n return {\n type: 'insert_column',\n table: op.table,\n after_column: op.column - 1,\n header: safeHeader,\n cells,\n reasoning: REVERT_REASONING,\n };\n}\n\nfunction inverseInsertTable(op: InsertTableOp): EditOperation {\n return {\n type: 'delete',\n target: op.table_id,\n reasoning: REVERT_REASONING,\n };\n}\n\nfunction inverseReplaceTable(\n op: ReplaceTableOp,\n docBefore: ProseMirrorNode,\n): EditOperation | null {\n const tableFound = findNodeBySynkId(docBefore, op.target);\n if (!tableFound) return null;\n\n const headers: { id: string; content: string }[] = [];\n const rows: { id: string; content: string }[][] = [];\n\n tableFound.node.forEach((row) => {\n if (row.type.name !== 'tableRow') return;\n const isHeaderRow = row.firstChild?.type.name === 'tableHeader';\n const cells: { id: string; content: string }[] = [];\n row.forEach((cell) => {\n const id = (cell.attrs[NODE_ID_ATTR] as string | undefined) ?? '';\n cells.push({ id, content: serializeCellInline(cell) });\n });\n if (isHeaderRow && headers.length === 0) {\n headers.push(...cells);\n } else {\n rows.push(cells);\n }\n });\n\n return {\n type: 'replace_table',\n target: op.target,\n headers,\n rows,\n reasoning: REVERT_REASONING,\n };\n}\n\n/** Find the Nth `tableRow` child of a table node (0-based). */\nfunction nthTableRow(tableNode: ProseMirrorNode, n: number): ProseMirrorNode | null {\n let idx = 0;\n let result: ProseMirrorNode | null = null;\n tableNode.forEach((child) => {\n if (child.type.name !== 'tableRow') return;\n if (idx === n) result = child;\n idx++;\n });\n return result;\n}\n\n/** Find the Nth cell child of a tableRow node (0-based). */\nfunction nthCell(rowNode: ProseMirrorNode, n: number): ProseMirrorNode | null {\n let idx = 0;\n let result: ProseMirrorNode | null = null;\n rowNode.forEach((child) => {\n if (idx === n) result = child;\n idx++;\n });\n return result;\n}\n\n/**\n * Capture a cell's content as an HTML fragment so the inverse op can feed it\n * back through the same parser used for forward ops. For multi-paragraph\n * cells this loses the per-paragraph synkIds — acceptable since revert\n * recreates the cell wholesale.\n */\nfunction serializeCellInline(cell: ProseMirrorNode): string {\n const parts: string[] = [];\n cell.forEach((child) => {\n if (child.type.name === 'paragraph') {\n parts.push(serializeInlineHtml(child));\n } else {\n parts.push(child.textContent);\n }\n });\n return parts.join(' ');\n}\n","/**\n * AgentJournal — per-session record of every edit tool dispatch.\n * See spec §8.3.\n *\n * Two revert mechanisms:\n * - `suggestionIds` set: reject each id via the suggestion-mode extension.\n * - `inverseOp` set: dispatch the inverse op via the existing applicator.\n */\n\nimport type { Editor } from '@tiptap/react';\nimport { applySingleOp } from '../utils/editApplicator';\nimport type { EditOperationWithStatus } from '../types/editOperations';\nimport type { AgentChange, EditOperation, EditOperationType } from './types';\n\nexport interface RecordChangeArgs {\n tool: EditOperationType;\n args: unknown;\n suggestionIds?: number[];\n inverseOp?: EditOperation;\n}\n\nexport interface RevertResult {\n ok: boolean;\n error?: string;\n}\n\nexport class AgentJournal {\n private changes: AgentChange[] = [];\n\n record(args: RecordChangeArgs): AgentChange {\n const change: AgentChange = {\n id: crypto.randomUUID(),\n tool: args.tool,\n args: args.args,\n suggestionIds: args.suggestionIds,\n inverseOp: args.inverseOp,\n appliedAt: Date.now(),\n };\n this.changes.push(change);\n return change;\n }\n\n list(activeOnly = true): AgentChange[] {\n if (!activeOnly) return [...this.changes];\n return this.changes.filter((c) => c.revertedAt == null);\n }\n\n revert(changeId: string, editor: Editor): RevertResult {\n const change = this.changes.find((c) => c.id === changeId);\n if (!change) return { ok: false, error: 'Change not found' };\n if (change.revertedAt != null) return { ok: false, error: 'Already reverted' };\n\n if (change.suggestionIds && change.suggestionIds.length > 0) {\n // Reject in reverse order so later marks don't shift earlier indices\n for (let i = change.suggestionIds.length - 1; i >= 0; i--) {\n editor.commands.rejectSuggestionById(change.suggestionIds[i]);\n }\n change.revertedAt = Date.now();\n return { ok: true };\n }\n\n if (change.inverseOp) {\n const result = applySingleOp(editor, change.inverseOp as EditOperationWithStatus);\n if (result.status !== 'applied') {\n return { ok: false, error: result.error ?? 'Inverse op failed' };\n }\n change.revertedAt = Date.now();\n return { ok: true };\n }\n\n return { ok: false, error: 'no revert capability recorded for this change' };\n }\n\n clear(): void {\n this.changes = [];\n }\n}\n","/**\n * Backend API client for editor chat sessions, history, and per-turn cost.\n *\n * Every export takes a `TiptapOfficeConfig` as its first argument. The library\n * itself owns no URL constants, no auth headers, and no env-var lookups —\n * everything comes from the config you pass to <TiptapOfficeProvider>.\n *\n * Your backend must expose:\n * POST {apiBaseUrl}/editor/chat → { chatId, created }\n * GET {apiBaseUrl}/editor/history?page&pageSize → { sessions, total, page, pageSize }\n * GET {apiBaseUrl}/editor/history/{chatId} → { chatId, documentId, chatTitle, messages }\n * POST {apiBaseUrl}/editor/history/{chatId}/append → ack body ignored\n * POST {apiBaseUrl}/llm/cost → cost breakdown (or omit; `null` is tolerated)\n *\n * The LLM provider proxy lives under `{apiBaseUrl}{llmProxyPath}` and is\n * handled by `agent/providers.ts`.\n */\n\nimport { buildFetchInit, type TiptapOfficeConfig } from '../config/TiptapOfficeProvider';\n\n// --- Chat sessions ---\n\nexport interface CreateChatResponse {\n chatId: string;\n created: boolean;\n}\n\nexport async function createChatSession(\n config: TiptapOfficeConfig,\n documentId: string,\n): Promise<CreateChatResponse> {\n const init = await buildFetchInit(config, {\n method: 'POST',\n body: JSON.stringify({ document_id: documentId }),\n });\n const res = await fetch(`${config.apiBaseUrl}/editor/chat`, init);\n\n if (!res.ok) {\n throw new Error(`Failed to create chat session: ${res.status}`);\n }\n\n const json = await res.json();\n return json.response ?? json;\n}\n\n// --- Chat history ---\n\nexport interface ChatSession {\n chatId: string;\n documentId: string;\n chatTitle: string;\n messageCount: number;\n lastEdited: string;\n}\n\nexport interface SessionListResponse {\n sessions: ChatSession[];\n total: number;\n page: number;\n pageSize: number;\n}\n\nexport async function getSessionList(\n config: TiptapOfficeConfig,\n page = 0,\n pageSize = 20,\n): Promise<SessionListResponse> {\n const init = await buildFetchInit(config, { method: 'GET' });\n const res = await fetch(\n `${config.apiBaseUrl}/editor/history?page=${page}&pageSize=${pageSize}`,\n init,\n );\n\n if (!res.ok) {\n throw new Error(`Failed to get session list: ${res.status}`);\n }\n\n const json = await res.json();\n return json.response ?? json;\n}\n\nexport interface ChatHistoryMessage {\n messageId: string;\n text: string;\n sentBy: 'USER' | 'SERVER';\n timestamp: string;\n}\n\nexport interface ChatMessagesResponse {\n chatId: string;\n documentId: string;\n chatTitle: string;\n messages: ChatHistoryMessage[];\n}\n\nexport async function getChatMessages(\n config: TiptapOfficeConfig,\n chatId: string,\n): Promise<ChatMessagesResponse> {\n const init = await buildFetchInit(config, { method: 'GET' });\n const res = await fetch(`${config.apiBaseUrl}/editor/history/${chatId}`, init);\n\n if (!res.ok) {\n throw new Error(`Failed to get chat messages: ${res.status}`);\n }\n\n const json = await res.json();\n return json.response ?? json;\n}\n\n// --- LLM cost computation (optional; returns null on any failure) ---\n\nexport interface TurnCostRequest {\n model: string;\n provider: 'anthropic' | 'openai' | 'google';\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens?: number;\n reasoningTokens?: number;\n}\n\nexport interface TurnCostResponse {\n model: string;\n provider: string;\n input_cost_usd: number;\n output_cost_usd: number;\n cached_input_cost_usd: number;\n reasoning_cost_usd: number;\n total_cost_usd: number;\n currency: 'USD';\n pricing_source: string;\n}\n\nexport async function fetchTurnCost(\n config: TiptapOfficeConfig,\n req: TurnCostRequest,\n): Promise<TurnCostResponse | null> {\n try {\n const init = await buildFetchInit(config, {\n method: 'POST',\n body: JSON.stringify({\n model: req.model,\n provider: req.provider,\n input_tokens: req.inputTokens,\n output_tokens: req.outputTokens,\n cached_input_tokens: req.cachedInputTokens ?? 0,\n reasoning_tokens: req.reasoningTokens ?? 0,\n }),\n });\n const res = await fetch(`${config.apiBaseUrl}/llm/cost`, init);\n if (!res.ok) return null;\n const json = await res.json();\n return (json.response ?? json) as TurnCostResponse;\n } catch {\n return null;\n }\n}\n","'use client';\n\nimport React from 'react';\nimport type { Editor } from '@tiptap/react';\nimport {\n Replace,\n Plus,\n Trash2,\n ArrowDown,\n ArrowUp,\n Table,\n Columns,\n RowsIcon,\n Eye,\n EyeOff,\n Check,\n CircleAlert,\n} from 'lucide-react';\nimport type { EditOperationWithStatus } from '../types/editOperations';\nimport { getNodeTextBySynkId } from '../utils/editApplicator';\nimport { useI18n } from '../i18n';\n\ninterface EditOperationCardProps {\n operation: EditOperationWithStatus;\n index: number;\n editor: Editor | null;\n onToggle: (index: number) => void;\n onApplySingle: (index: number) => void;\n}\n\nconst OP_ICONS: Record<string, React.ReactNode> = {\n replace_text: <Replace size={14} />,\n replace_paragraph: <Replace size={14} />,\n insert_after: <ArrowDown size={14} />,\n insert_before: <ArrowUp size={14} />,\n delete: <Trash2 size={14} />,\n replace_section: <Replace size={14} />,\n replace_cell: <Replace size={14} />,\n insert_row: <RowsIcon size={14} />,\n delete_row: <Trash2 size={14} />,\n insert_column: <Columns size={14} />,\n delete_column: <Trash2 size={14} />,\n insert_table: <Table size={14} />,\n replace_table: <Table size={14} />,\n};\n\nconst STATUS_STYLES: Record<string, string> = {\n pending: 'border-stone-200 dark:border-stone-700',\n applied: 'border-green-300 dark:border-green-700 bg-green-50/50 dark:bg-green-950/20',\n failed: 'border-red-300 dark:border-red-700 bg-red-50/50 dark:bg-red-950/20',\n skipped: 'border-stone-200 dark:border-stone-700 opacity-50',\n conflicted: 'border-amber-300 dark:border-amber-700 bg-amber-50/50 dark:bg-amber-950/20',\n};\n\nfunction formatOpType(type: string): string {\n return type.replace(/_/g, ' ');\n}\n\nfunction getTargetId(op: EditOperationWithStatus): string {\n if ('target' in op) return op.target;\n if ('table' in op) return (op as { table: string }).table;\n if ('after' in op) return (op as { after: string }).after;\n return '';\n}\n\n/** Get the current text of a node, used for diffing */\nfunction getCurrentContent(editor: Editor | null, synkId: string): string {\n if (!editor) return '';\n return getNodeTextBySynkId(editor, synkId);\n}\n\n/** Renders a git-style diff block */\nfunction DiffBlock({\n oldLines,\n newLines,\n}: {\n oldLines?: string[];\n newLines?: string[];\n}) {\n return (\n <div className=\"mt-2 rounded-md border border-stone-200 dark:border-stone-700 overflow-hidden text-xs font-mono\">\n {oldLines &&\n oldLines.map((line, i) => (\n <div\n key={`old-${i}`}\n className=\"flex items-start bg-red-50 dark:bg-red-950/30 border-b border-stone-100 dark:border-stone-800 last:border-b-0\"\n >\n <span className=\"flex-shrink-0 w-6 text-center text-red-400 dark:text-red-500 select-none py-0.5\">\n -\n </span>\n <span className=\"text-red-700 dark:text-red-300 py-0.5 pr-2 break-all whitespace-pre-wrap\">\n {line}\n </span>\n </div>\n ))}\n {newLines &&\n newLines.map((line, i) => (\n <div\n key={`new-${i}`}\n className=\"flex items-start bg-green-50 dark:bg-green-950/30 border-b border-stone-100 dark:border-stone-800 last:border-b-0\"\n >\n <span className=\"flex-shrink-0 w-6 text-center text-green-400 dark:text-green-500 select-none py-0.5\">\n +\n </span>\n <span className=\"text-green-700 dark:text-green-300 py-0.5 pr-2 break-all whitespace-pre-wrap\">\n {line}\n </span>\n </div>\n ))}\n </div>\n );\n}\n\n/** Split text into displayable lines, trimming but preserving structure */\nfunction toLines(text: string): string[] {\n if (!text) return [];\n const lines = text.split('\\n');\n // Filter empty trailing lines but keep meaningful content\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') {\n lines.pop();\n }\n return lines.length > 0 ? lines : [text];\n}\n\nconst EditOperationCard: React.FC<EditOperationCardProps> = ({\n operation,\n index,\n editor,\n onToggle,\n onApplySingle,\n}) => {\n const { t } = useI18n();\n const isPending = operation.status === 'pending';\n const isSkipped = operation.status === 'skipped';\n const isApplied = operation.status === 'applied';\n const isFailed = operation.status === 'failed';\n const statusStyle = STATUS_STYLES[operation.status || 'pending'] || STATUS_STYLES.pending;\n\n // Build diff data based on operation type\n const renderDiff = () => {\n switch (operation.type) {\n case 'replace_text': {\n return (\n <DiffBlock\n oldLines={toLines(operation.find)}\n newLines={toLines(operation.replace)}\n />\n );\n }\n case 'replace_paragraph': {\n const current = getCurrentContent(editor, operation.target);\n return (\n <DiffBlock\n oldLines={current ? toLines(current) : undefined}\n newLines={toLines(operation.content)}\n />\n );\n }\n case 'insert_after':\n case 'insert_before': {\n return <DiffBlock newLines={toLines(operation.content)} />;\n }\n case 'delete': {\n const current = getCurrentContent(editor, operation.target);\n return (\n <DiffBlock\n oldLines={current ? toLines(current) : [t('editor.ai.nodeWillBeDeleted')]}\n />\n );\n }\n case 'replace_cell': {\n const current = getCurrentContent(editor, operation.target);\n const newContent = operation.paragraphs\n ? operation.paragraphs.map((p) => p.content).join('\\n')\n : operation.content || '';\n return (\n <DiffBlock\n oldLines={current ? toLines(current) : undefined}\n newLines={toLines(newContent)}\n />\n );\n }\n case 'replace_section': {\n return <DiffBlock newLines={toLines(operation.content)} />;\n }\n case 'insert_row': {\n const cells = operation.cells.map((c) => c.content).join(' | ');\n return <DiffBlock newLines={[`| ${cells} |`]} />;\n }\n case 'delete_row': {\n return (\n <DiffBlock\n oldLines={[`Row ${operation.row + 1} in table ${operation.table}`]}\n />\n );\n }\n case 'insert_column': {\n const header = operation.header.content;\n return <DiffBlock newLines={[`Column: ${header}`]} />;\n }\n case 'delete_column': {\n return (\n <DiffBlock\n oldLines={[`Column ${operation.column + 1} in table ${operation.table}`]}\n />\n );\n }\n case 'insert_table': {\n const headerRow = operation.headers.map((h) => h.content).join(' | ');\n const lines = [`| ${headerRow} |`];\n for (const row of operation.rows) {\n lines.push(`| ${row.map((c) => c.content).join(' | ')} |`);\n }\n return <DiffBlock newLines={lines} />;\n }\n case 'replace_table': {\n const headerRow = operation.headers.map((h) => h.content).join(' | ');\n const lines = [`| ${headerRow} |`];\n for (const row of operation.rows) {\n lines.push(`| ${row.map((c) => c.content).join(' | ')} |`);\n }\n return (\n <DiffBlock\n oldLines={[`[table ${operation.target}]`]}\n newLines={lines}\n />\n );\n }\n default:\n return null;\n }\n };\n\n return (\n <div className={`border rounded-lg p-3 transition-all ${statusStyle}`}>\n {/* Header row */}\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"text-stone-500 dark:text-stone-400 flex-shrink-0\">\n {OP_ICONS[operation.type] || <Replace size={14} />}\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-xs font-medium uppercase tracking-wide text-stone-500 dark:text-stone-400\">\n {formatOpType(operation.type)}\n </span>\n <code className=\"text-xs px-1.5 py-0.5 bg-stone-100 dark:bg-stone-800 rounded text-stone-600 dark:text-stone-300 font-mono\">\n {getTargetId(operation)}\n </code>\n {isApplied && (\n <span className=\"inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400 font-medium\">\n <Check size={12} />\n {t('editor.ai.applied')}\n </span>\n )}\n {isFailed && (\n <span className=\"inline-flex items-center gap-1 text-xs text-red-600 dark:text-red-400 font-medium\">\n <CircleAlert size={12} />\n {t('editor.ai.failed')}\n </span>\n )}\n </div>\n </div>\n </div>\n\n {/* Actions for pending/skipped operations */}\n {(isPending || isSkipped) && (\n <div className=\"flex items-center gap-1 flex-shrink-0\">\n {isPending && (\n <button\n onClick={() => onApplySingle(index)}\n className=\"px-2 py-0.5 text-xs font-medium rounded bg-[#111111] text-white hover:bg-[#222222] transition-colors\"\n title={t('editor.ai.applySingle')}\n >\n {t('editor.ai.applySingle')}\n </button>\n )}\n <button\n onClick={() => onToggle(index)}\n className=\"p-1 rounded hover:bg-stone-100 dark:hover:bg-stone-700 transition-colors\"\n title={isSkipped ? t('editor.ai.include') : t('editor.ai.skip')}\n >\n {isSkipped ? (\n <EyeOff size={16} className=\"text-stone-400\" />\n ) : (\n <Eye size={16} className=\"text-stone-600 dark:text-stone-300\" />\n )}\n </button>\n </div>\n )}\n </div>\n\n {/* Reasoning */}\n <p className=\"text-sm text-stone-600 dark:text-stone-300 mt-1.5 line-clamp-2\">\n {operation.reasoning}\n </p>\n\n {/* Error message */}\n {operation.error && (\n <p className=\"text-xs text-red-500 mt-1\">{operation.error}</p>\n )}\n\n {/* Git-like diff */}\n {!isSkipped && renderDiff()}\n </div>\n );\n};\n\nexport default EditOperationCard;\n","import JSZip from 'jszip';\n\n// OOXML namespace\nconst W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';\nconst R_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';\nconst WP_NS = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\nconst A_NS = 'http://schemas.openxmlformats.org/drawingml/2006/main';\nconst PIC_NS = 'http://schemas.openxmlformats.org/drawingml/2006/picture';\n\n// --- Helpers ---\n\nfunction getWAttr(el: Element, name: string): string | null {\n return el.getAttributeNS(W_NS, name) || el.getAttribute(`w:${name}`) || el.getAttribute(name);\n}\n\nfunction getRAttr(el: Element, name: string): string | null {\n return el.getAttributeNS(R_NS, name) || el.getAttribute(`r:${name}`);\n}\n\nfunction findChild(el: Element, localName: string): Element | null {\n for (const child of Array.from(el.children)) {\n if (child.localName === localName) return child;\n }\n return null;\n}\n\nfunction findChildren(el: Element, localName: string): Element[] {\n return Array.from(el.children).filter(c => c.localName === localName);\n}\n\nfunction findNested(el: Element, ...path: string[]): Element | null {\n let current: Element | null = el;\n for (const name of path) {\n if (!current) return null;\n current = findChild(current, name);\n }\n return current;\n}\n\nfunction parseIntVal(el: Element, attrName: string = 'val'): number | undefined {\n const v = getWAttr(el, attrName);\n if (v) {\n const n = parseInt(v, 10);\n return isNaN(n) ? undefined : n;\n }\n return undefined;\n}\n\nfunction twipsToPx(twips: number): number {\n return Math.round(twips / 15);\n}\n\nfunction escapeHtml(str: string): string {\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\n// --- Types ---\n\ninterface StyleDef {\n name?: string;\n basedOn?: string;\n indentLeft?: number;\n indentRight?: number;\n indentHanging?: number;\n indentFirstLine?: number;\n alignment?: string;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strike?: boolean;\n fontSize?: number;\n color?: string;\n fontFamily?: string;\n}\n\ninterface NumberingLevel {\n format: string; // 'bullet', 'decimal', 'lowerLetter', etc.\n text: string;\n}\n\ninterface DocxComment {\n id: string;\n author: string;\n date: string;\n text: string;\n}\n\nexport interface DocxAnnotationResult {\n html: string;\n comments: {\n id: string;\n author: { username: string; isAI: boolean };\n text: string;\n replies: never[];\n resolved: boolean;\n severity: 'moderate';\n createdAt: string;\n from: number;\n to: number;\n selectedText: string;\n }[];\n}\n\ninterface ConvertContext {\n styles: Map<string, StyleDef>;\n abstractNums: Map<string, Map<number, NumberingLevel>>;\n numToAbstract: Map<string, string>;\n relationships: Map<string, string>;\n images: Map<string, string>; // path -> base64 data URL\n // Annotation tracking\n comments: Map<string, DocxComment>;\n activeCommentIds: Set<string>;\n commentTextMap: Map<string, string>; // commentId -> selected text accumulated\n suggestionIdCounter: number;\n}\n\n// --- Parsing ---\n\nfunction parseStyles(doc: Document): Map<string, StyleDef> {\n const styles = new Map<string, StyleDef>();\n const styleEls = doc.getElementsByTagNameNS(W_NS, 'style');\n if (styleEls.length === 0) {\n // Fallback: try without namespace\n const allStyles = doc.querySelectorAll('style');\n // OOXML style elements are different from HTML style elements\n }\n\n for (const el of Array.from(styleEls)) {\n const id = getWAttr(el, 'styleId');\n if (!id) continue;\n\n const def: StyleDef = {};\n const nameEl = findChild(el, 'name');\n if (nameEl) def.name = getWAttr(nameEl, 'val') || undefined;\n const basedOnEl = findChild(el, 'basedOn');\n if (basedOnEl) def.basedOn = getWAttr(basedOnEl, 'val') || undefined;\n\n const pPr = findChild(el, 'pPr');\n if (pPr) {\n const ind = findChild(pPr, 'ind');\n if (ind) {\n def.indentLeft = parseIntVal(ind, 'left') ?? parseIntVal(ind, 'start');\n def.indentRight = parseIntVal(ind, 'right') ?? parseIntVal(ind, 'end');\n def.indentHanging = parseIntVal(ind, 'hanging');\n def.indentFirstLine = parseIntVal(ind, 'firstLine');\n }\n const jc = findChild(pPr, 'jc');\n if (jc) def.alignment = getWAttr(jc, 'val') || undefined;\n }\n\n const rPr = findChild(el, 'rPr');\n if (rPr) {\n if (findChild(rPr, 'b')) def.bold = true;\n if (findChild(rPr, 'i')) def.italic = true;\n if (findChild(rPr, 'u')) def.underline = true;\n if (findChild(rPr, 'strike')) def.strike = true;\n const sz = findChild(rPr, 'sz');\n if (sz) def.fontSize = parseIntVal(sz);\n const color = findChild(rPr, 'color');\n if (color) def.color = getWAttr(color, 'val') || undefined;\n const rFonts = findChild(rPr, 'rFonts');\n if (rFonts) def.fontFamily = getWAttr(rFonts, 'ascii') || undefined;\n }\n\n styles.set(id, def);\n }\n return styles;\n}\n\nfunction parseNumbering(doc: Document): { abstractNums: Map<string, Map<number, NumberingLevel>>; numToAbstract: Map<string, string> } {\n const abstractNums = new Map<string, Map<number, NumberingLevel>>();\n const numToAbstract = new Map<string, string>();\n\n for (const an of Array.from(doc.getElementsByTagNameNS(W_NS, 'abstractNum'))) {\n const id = getWAttr(an, 'abstractNumId');\n if (!id) continue;\n const levels = new Map<number, NumberingLevel>();\n for (const lvl of findChildren(an, 'lvl')) {\n const ilvl = parseIntVal(lvl, 'ilvl') ?? 0;\n const numFmt = findChild(lvl, 'numFmt');\n const lvlText = findChild(lvl, 'lvlText');\n levels.set(ilvl, {\n format: numFmt ? (getWAttr(numFmt, 'val') || 'bullet') : 'bullet',\n text: lvlText ? (getWAttr(lvlText, 'val') || '') : '',\n });\n }\n abstractNums.set(id, levels);\n }\n\n for (const num of Array.from(doc.getElementsByTagNameNS(W_NS, 'num'))) {\n const numId = getWAttr(num, 'numId');\n const absRef = findChild(num, 'abstractNumId');\n if (numId && absRef) {\n const absId = getWAttr(absRef, 'val');\n if (absId) numToAbstract.set(numId, absId);\n }\n }\n\n return { abstractNums, numToAbstract };\n}\n\nfunction parseRelationships(doc: Document): Map<string, string> {\n const rels = new Map<string, string>();\n for (const el of Array.from(doc.getElementsByTagName('Relationship'))) {\n const id = el.getAttribute('Id');\n const target = el.getAttribute('Target');\n if (id && target) rels.set(id, target);\n }\n return rels;\n}\n\nfunction parseComments(doc: Document): Map<string, DocxComment> {\n const comments = new Map<string, DocxComment>();\n const commentEls = doc.getElementsByTagNameNS(W_NS, 'comment');\n for (const el of Array.from(commentEls)) {\n const id = getWAttr(el, 'id');\n if (!id) continue;\n const author = getWAttr(el, 'author') || 'Unknown';\n const date = getWAttr(el, 'date') || '';\n // Extract text from all paragraphs/runs inside the comment\n let text = '';\n const paragraphs = el.getElementsByTagNameNS(W_NS, 'p');\n for (const p of Array.from(paragraphs)) {\n const runs = p.getElementsByTagNameNS(W_NS, 'r');\n for (const r of Array.from(runs)) {\n const tEls = r.getElementsByTagNameNS(W_NS, 't');\n for (const t of Array.from(tEls)) {\n text += t.textContent || '';\n }\n }\n text += '\\n';\n }\n comments.set(id, { id, author, date, text: text.trim() });\n }\n return comments;\n}\n\nasync function loadImages(zip: JSZip, relationships: Map<string, string>): Promise<Map<string, string>> {\n const images = new Map<string, string>();\n for (const [, target] of relationships) {\n if (/\\.(png|jpg|jpeg|gif|bmp|svg|webp|tiff?)$/i.test(target)) {\n const path = target.startsWith('/') ? target.slice(1) : `word/${target}`;\n const file = zip.file(path);\n if (file) {\n try {\n const data = await file.async('base64');\n const ext = target.split('.').pop()!.toLowerCase();\n const mime = ext === 'jpg' ? 'jpeg' : ext;\n images.set(target, `data:image/${mime};base64,${data}`);\n } catch {\n // skip broken images\n }\n }\n }\n }\n return images;\n}\n\n// --- Conversion ---\n\nfunction isListParagraph(p: Element): boolean {\n return !!findNested(p, 'pPr', 'numPr', 'numId');\n}\n\nfunction getListInfo(p: Element, ctx: ConvertContext): { numId: string; ilvl: number; isBullet: boolean } | null {\n const numPr = findNested(p, 'pPr', 'numPr');\n if (!numPr) return null;\n\n const numIdEl = findChild(numPr, 'numId');\n const ilvlEl = findChild(numPr, 'ilvl');\n const numId = numIdEl ? (getWAttr(numIdEl, 'val') || '0') : '0';\n const ilvl = ilvlEl ? (parseInt(getWAttr(ilvlEl, 'val') || '0') || 0) : 0;\n\n if (numId === '0') return null; // numId 0 means no numbering\n\n let isBullet = true;\n const absId = ctx.numToAbstract.get(numId);\n if (absId) {\n const levels = ctx.abstractNums.get(absId);\n if (levels) {\n const level = levels.get(ilvl);\n if (level && level.format !== 'bullet') isBullet = false;\n }\n }\n\n return { numId, ilvl, isBullet };\n}\n\nfunction wrapWithCommentSpans(html: string, activeCommentIds: Set<string>): string {\n if (activeCommentIds.size === 0 || !html) return html;\n let wrapped = html;\n for (const commentId of activeCommentIds) {\n wrapped = `<span data-comment-id=\"docx-comment-${commentId}\" data-comment-severity=\"moderate\">${wrapped}</span>`;\n }\n return wrapped;\n}\n\nfunction convertRuns(parent: Element, ctx: ConvertContext): string {\n let html = '';\n\n for (const child of Array.from(parent.children)) {\n if (child.localName === 'commentRangeStart') {\n const id = getWAttr(child, 'id');\n if (id) ctx.activeCommentIds.add(id);\n } else if (child.localName === 'commentRangeEnd') {\n const id = getWAttr(child, 'id');\n if (id) ctx.activeCommentIds.delete(id);\n } else if (child.localName === 'r') {\n // Skip comment reference runs (the small superscript marker)\n const rPr = findChild(child, 'rPr');\n const rStyle = rPr ? findChild(rPr, 'rStyle') : null;\n if (rStyle && getWAttr(rStyle, 'val') === 'CommentReference') continue;\n\n let runHtml = convertRun(child, ctx);\n // Accumulate selected text for active comments\n const plainText = (child.textContent || '').trim();\n for (const commentId of ctx.activeCommentIds) {\n ctx.commentTextMap.set(commentId, (ctx.commentTextMap.get(commentId) || '') + plainText);\n }\n runHtml = wrapWithCommentSpans(runHtml, ctx.activeCommentIds);\n html += runHtml;\n } else if (child.localName === 'ins') {\n // Tracked change: insertion\n const suggId = ctx.suggestionIdCounter++;\n const inner = convertRuns(child, ctx);\n html += inner ? `<ins data-id=\"${suggId}\">${inner}</ins>` : '';\n } else if (child.localName === 'del') {\n // Tracked change: deletion\n const suggId = ctx.suggestionIdCounter++;\n const inner = convertDeletedRuns(child, ctx);\n html += inner ? `<del data-id=\"${suggId}\">${inner}</del>` : '';\n } else if (child.localName === 'hyperlink') {\n const rId = getRAttr(child, 'id');\n const url = rId ? ctx.relationships.get(rId) : null;\n const inner = convertRuns(child, ctx);\n html += url ? `<a href=\"${escapeHtml(url)}\">${inner}</a>` : inner;\n } else if (child.localName === 'bookmarkStart' || child.localName === 'bookmarkEnd') {\n // skip bookmarks\n }\n }\n\n return html;\n}\n\n/** Convert runs inside a <w:del> element — uses <w:delText> instead of <w:t> */\nfunction convertDeletedRuns(parent: Element, ctx: ConvertContext): string {\n let html = '';\n for (const child of Array.from(parent.children)) {\n if (child.localName === 'r') {\n const rPr = findChild(child, 'rPr');\n const pieces: string[] = [];\n\n for (const rc of Array.from(child.children)) {\n if (rc.localName === 'delText') {\n pieces.push(escapeHtml(rc.textContent || ''));\n } else if (rc.localName === 't') {\n pieces.push(escapeHtml(rc.textContent || ''));\n }\n }\n\n let text = pieces.join('');\n if (!text) continue;\n\n // Apply inline formatting\n if (rPr) {\n if (findChild(rPr, 'b')) text = `<strong>${text}</strong>`;\n if (findChild(rPr, 'i')) text = `<em>${text}</em>`;\n if (findChild(rPr, 'u')) text = `<u>${text}</u>`;\n }\n\n html += wrapWithCommentSpans(text, ctx.activeCommentIds);\n } else if (child.localName === 'commentRangeStart') {\n const id = getWAttr(child, 'id');\n if (id) ctx.activeCommentIds.add(id);\n } else if (child.localName === 'commentRangeEnd') {\n const id = getWAttr(child, 'id');\n if (id) ctx.activeCommentIds.delete(id);\n }\n }\n return html;\n}\n\nfunction convertRun(r: Element, ctx: ConvertContext): string {\n const rPr = findChild(r, 'rPr');\n let pieces: string[] = [];\n\n for (const child of Array.from(r.children)) {\n if (child.localName === 't') {\n pieces.push(escapeHtml(child.textContent || ''));\n } else if (child.localName === 'br') {\n const type = getWAttr(child, 'type');\n if (type === 'page') {\n pieces.push('<br data-page-break=\"true\">');\n } else {\n pieces.push('<br>');\n }\n } else if (child.localName === 'tab') {\n pieces.push('&emsp;');\n } else if (child.localName === 'drawing' || child.localName === 'pict') {\n const imgHtml = convertImage(child, ctx);\n if (imgHtml) pieces.push(imgHtml);\n }\n }\n\n let text = pieces.join('');\n if (!text) return '';\n\n if (!rPr) return text;\n\n // Inline styles\n const styleProps: string[] = [];\n let wrapBold = false, wrapItalic = false, wrapUnderline = false, wrapStrike = false;\n let wrapSup = false, wrapSub = false;\n\n for (const prop of Array.from(rPr.children)) {\n switch (prop.localName) {\n case 'b': {\n const val = getWAttr(prop, 'val');\n if (val !== '0' && val !== 'false') wrapBold = true;\n break;\n }\n case 'i': {\n const val = getWAttr(prop, 'val');\n if (val !== '0' && val !== 'false') wrapItalic = true;\n break;\n }\n case 'u':\n wrapUnderline = true;\n break;\n case 'strike':\n wrapStrike = true;\n break;\n case 'color': {\n const c = getWAttr(prop, 'val');\n if (c && c !== 'auto') styleProps.push(`color: #${c}`);\n break;\n }\n case 'sz': {\n const sz = parseIntVal(prop);\n if (sz) styleProps.push(`font-size: ${sz / 2}pt`);\n break;\n }\n case 'highlight': {\n const c = getWAttr(prop, 'val');\n const hex = highlightToHex(c);\n if (hex) text = `<mark data-color=\"${hex}\" style=\"background-color: ${hex}\">${text}</mark>`;\n break;\n }\n case 'rFonts': {\n const font = getWAttr(prop, 'ascii');\n if (font) styleProps.push(`font-family: ${font}`);\n break;\n }\n case 'vertAlign': {\n const val = getWAttr(prop, 'val');\n if (val === 'superscript') wrapSup = true;\n if (val === 'subscript') wrapSub = true;\n break;\n }\n }\n }\n\n if (styleProps.length > 0) {\n text = `<span style=\"${styleProps.join('; ')}\">${text}</span>`;\n }\n if (wrapBold) text = `<strong>${text}</strong>`;\n if (wrapItalic) text = `<em>${text}</em>`;\n if (wrapUnderline) text = `<u>${text}</u>`;\n if (wrapStrike) text = `<s>${text}</s>`;\n if (wrapSup) text = `<sup>${text}</sup>`;\n if (wrapSub) text = `<sub>${text}</sub>`;\n\n return text;\n}\n\nfunction convertImage(el: Element, ctx: ConvertContext): string | null {\n // Look for r:embed in nested blip elements\n const blip = findDeep(el, 'blip');\n if (!blip) return null;\n\n const embed = getRAttr(blip, 'embed');\n if (!embed) return null;\n\n const target = ctx.relationships.get(embed);\n if (!target) return null;\n\n const dataUrl = ctx.images.get(target);\n if (!dataUrl) return null;\n\n // Try to get dimensions from extent element\n const extent = findDeep(el, 'extent');\n let width = '';\n if (extent) {\n const cx = extent.getAttribute('cx');\n if (cx) {\n // EMUs to pixels: 1 inch = 914400 EMUs, 1 inch = 96 px\n const px = Math.round(parseInt(cx) / 914400 * 96);\n if (px > 0) width = ` width=\"${px}\"`;\n }\n }\n\n return `<img src=\"${dataUrl}\"${width}>`;\n}\n\nfunction findDeep(el: Element, localName: string): Element | null {\n for (const child of Array.from(el.children)) {\n if (child.localName === localName) return child;\n const found = findDeep(child, localName);\n if (found) return found;\n }\n return null;\n}\n\nfunction convertParagraph(p: Element, ctx: ConvertContext): string {\n const pPr = findChild(p, 'pPr');\n let tag = 'p';\n const styles: string[] = [];\n const attrs: string[] = [];\n\n if (pPr) {\n // Heading style\n const pStyle = findChild(pPr, 'pStyle');\n if (pStyle) {\n const styleId = getWAttr(pStyle, 'val');\n if (styleId) {\n const headingMatch = styleId.match(/^[Hh]eading(\\d)$/);\n if (headingMatch) {\n tag = `h${headingMatch[1]}`;\n } else {\n const styleDef = ctx.styles.get(styleId);\n if (styleDef?.name) {\n const nameMatch = styleDef.name.match(/heading\\s*(\\d)/i);\n if (nameMatch) tag = `h${nameMatch[1]}`;\n // Map \"Quote\" style to blockquote handled at call site\n }\n }\n\n // Inherit indentation from style\n const styleDef = ctx.styles.get(styleId);\n if (styleDef?.indentLeft && styleDef.indentLeft > 0) {\n const px = twipsToPx(styleDef.indentLeft);\n const level = Math.max(1, Math.round(styleDef.indentLeft / 720));\n styles.push(`margin-left: ${px}px`);\n attrs.push(`data-indent=\"${level}\"`);\n }\n }\n }\n\n // Direct indentation (overrides style)\n const ind = findChild(pPr, 'ind');\n if (ind) {\n const left = parseIntVal(ind, 'left') ?? parseIntVal(ind, 'start');\n if (left && left > 0) {\n const px = twipsToPx(left);\n const level = Math.max(1, Math.round(left / 720));\n // Replace any style-inherited indent\n const existingIdx = styles.findIndex(s => s.startsWith('margin-left'));\n if (existingIdx >= 0) styles.splice(existingIdx, 1);\n styles.push(`margin-left: ${px}px`);\n // Replace existing data-indent\n const attrIdx = attrs.findIndex(a => a.startsWith('data-indent'));\n if (attrIdx >= 0) attrs.splice(attrIdx, 1);\n attrs.push(`data-indent=\"${level}\"`);\n }\n const firstLine = parseIntVal(ind, 'firstLine');\n if (firstLine && firstLine > 0) {\n styles.push(`text-indent: ${twipsToPx(firstLine)}px`);\n }\n }\n\n // Alignment\n const jc = findChild(pPr, 'jc');\n if (jc) {\n const val = getWAttr(jc, 'val');\n if (val === 'center') styles.push('text-align: center');\n else if (val === 'right') styles.push('text-align: right');\n else if (val === 'both' || val === 'distribute') styles.push('text-align: justify');\n }\n }\n\n const inner = convertRuns(p, ctx);\n const styleAttr = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const extraAttrs = attrs.length > 0 ? ` ${attrs.join(' ')}` : '';\n\n return `<${tag}${extraAttrs}${styleAttr}>${inner}</${tag}>`;\n}\n\n// --- Table conversion ---\n\ninterface CellInfo {\n el: Element;\n colspan: number;\n rowspan: number;\n skip: boolean;\n gridCol: number;\n bgColor?: string;\n isHeader: boolean;\n}\n\nfunction convertTable(tbl: Element, ctx: ConvertContext): string {\n // Column widths from tblGrid\n const tblGrid = findChild(tbl, 'tblGrid');\n const gridColWidths: number[] = [];\n if (tblGrid) {\n for (const gc of findChildren(tblGrid, 'gridCol')) {\n const w = parseIntVal(gc, 'w');\n if (w) gridColWidths.push(w);\n }\n }\n\n const trEls = findChildren(tbl, 'tr');\n if (trEls.length === 0) return '';\n\n // Build cell grid\n const grid: CellInfo[][] = [];\n\n for (let rowIdx = 0; rowIdx < trEls.length; rowIdx++) {\n const tr = trEls[rowIdx];\n const trPr = findChild(tr, 'trPr');\n const isHeaderRow = rowIdx === 0 || !!(trPr && findChild(trPr, 'tblHeader'));\n\n const tcEls = findChildren(tr, 'tc');\n const row: CellInfo[] = [];\n let gridCol = 0;\n\n // Skip columns occupied by rowspans from previous rows\n const isOccupied = (col: number): boolean => {\n for (let r = 0; r < rowIdx; r++) {\n for (const cell of grid[r]) {\n if (cell.skip) continue;\n if (col >= cell.gridCol && col < cell.gridCol + cell.colspan && r + cell.rowspan > rowIdx) {\n return true;\n }\n }\n }\n return false;\n };\n\n for (const tc of tcEls) {\n while (isOccupied(gridCol)) gridCol++;\n\n const tcPr = findChild(tc, 'tcPr');\n let colspan = 1;\n let isVMergeRestart = false;\n let isVMergeContinue = false;\n let bgColor: string | undefined;\n\n if (tcPr) {\n const gs = findChild(tcPr, 'gridSpan');\n if (gs) colspan = parseInt(getWAttr(gs, 'val') || '1') || 1;\n\n const vm = findChild(tcPr, 'vMerge');\n if (vm) {\n const val = getWAttr(vm, 'val');\n if (val === 'restart') isVMergeRestart = true;\n else isVMergeContinue = true;\n }\n\n const shd = findChild(tcPr, 'shd');\n if (shd) {\n const fill = getWAttr(shd, 'fill');\n if (fill && fill !== 'auto') bgColor = fill;\n }\n }\n\n row.push({\n el: tc,\n colspan,\n rowspan: 1,\n skip: isVMergeContinue,\n gridCol,\n bgColor,\n isHeader: isHeaderRow,\n });\n\n gridCol += colspan;\n }\n\n grid.push(row);\n }\n\n // Compute rowspans: for each vMerge restart, count continuation cells below\n for (let rowIdx = 0; rowIdx < grid.length; rowIdx++) {\n for (const cell of grid[rowIdx]) {\n if (cell.skip) continue;\n const tcPr = findChild(cell.el, 'tcPr');\n const vm = tcPr ? findChild(tcPr, 'vMerge') : null;\n if (!vm || getWAttr(vm, 'val') !== 'restart') continue;\n\n let span = 1;\n for (let r = rowIdx + 1; r < grid.length; r++) {\n const below = grid[r].find(c => c.gridCol === cell.gridCol);\n if (below && below.skip) {\n span++;\n } else {\n break;\n }\n }\n cell.rowspan = span;\n }\n }\n\n // Render HTML\n let html = '<table>';\n\n for (const row of grid) {\n html += '<tr>';\n for (const cell of row) {\n if (cell.skip) continue;\n\n const tag = cell.isHeader ? 'th' : 'td';\n const cellAttrs: string[] = [];\n\n if (cell.colspan > 1) cellAttrs.push(`colspan=\"${cell.colspan}\"`);\n if (cell.rowspan > 1) cellAttrs.push(`rowspan=\"${cell.rowspan}\"`);\n\n // Column widths for TipTap\n if (gridColWidths.length > 0) {\n const widths: number[] = [];\n for (let c = cell.gridCol; c < cell.gridCol + cell.colspan && c < gridColWidths.length; c++) {\n widths.push(twipsToPx(gridColWidths[c]));\n }\n if (widths.length > 0) cellAttrs.push(`colwidth=\"${widths.join(',')}\"`);\n }\n\n if (cell.bgColor) cellAttrs.push(`style=\"background-color: #${cell.bgColor}\"`);\n\n // Cell content: paragraphs\n const paragraphs = findChildren(cell.el, 'p');\n let content = paragraphs.map(p => convertParagraph(p, ctx)).join('');\n if (!content) content = '<p></p>';\n\n const attrStr = cellAttrs.length > 0 ? ' ' + cellAttrs.join(' ') : '';\n html += `<${tag}${attrStr}>${content}</${tag}>`;\n }\n html += '</tr>';\n }\n\n html += '</table>';\n return html;\n}\n\n// --- List conversion ---\n\nfunction convertListRun(\n elements: Element[],\n startIdx: number,\n ctx: ConvertContext\n): { html: string; nextIdx: number } {\n const firstInfo = getListInfo(elements[startIdx], ctx);\n if (!firstInfo) return { html: '', nextIdx: startIdx + 1 };\n\n const tag = firstInfo.isBullet ? 'ul' : 'ol';\n let html = `<${tag}>`;\n\n let i = startIdx;\n while (i < elements.length) {\n const el = elements[i];\n if (el.localName !== 'p') break;\n\n const info = getListInfo(el, ctx);\n if (!info || info.numId !== firstInfo.numId) break;\n\n // Handle nested lists: if ilvl increases, recurse\n if (info.ilvl > firstInfo.ilvl) {\n const nested = convertListRun(elements, i, ctx);\n // Append nested list to the last <li>\n html += nested.html;\n i = nested.nextIdx;\n continue;\n }\n if (info.ilvl < firstInfo.ilvl) break;\n\n html += `<li>${convertRuns(el, ctx)}</li>`;\n i++;\n }\n\n html += `</${tag}>`;\n return { html, nextIdx: i };\n}\n\n// --- Blockquote detection ---\n\nfunction isBlockquote(p: Element, ctx: ConvertContext): boolean {\n const pPr = findChild(p, 'pPr');\n if (!pPr) return false;\n const pStyle = findChild(pPr, 'pStyle');\n if (!pStyle) return false;\n const styleId = getWAttr(pStyle, 'val');\n if (!styleId) return false;\n const styleDef = ctx.styles.get(styleId);\n if (!styleDef?.name) return false;\n return /^(quote|block\\s*quote|intense\\s*quote)/i.test(styleDef.name);\n}\n\n// --- Main export ---\n\nasync function buildContext(arrayBuffer: ArrayBuffer): Promise<{ ctx: ConvertContext; doc: Document; zip: JSZip }> {\n const zip = await JSZip.loadAsync(arrayBuffer);\n\n // Read required files\n const documentXml = await zip.file('word/document.xml')?.async('string');\n if (!documentXml) throw new Error('Invalid DOCX: missing word/document.xml');\n\n const stylesXml = await zip.file('word/styles.xml')?.async('string');\n const numberingXml = await zip.file('word/numbering.xml')?.async('string');\n const relsXml = await zip.file('word/_rels/document.xml.rels')?.async('string');\n const commentsXml = await zip.file('word/comments.xml')?.async('string');\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(documentXml, 'application/xml');\n\n const styles = stylesXml\n ? parseStyles(parser.parseFromString(stylesXml, 'application/xml'))\n : new Map<string, StyleDef>();\n\n let abstractNums = new Map<string, Map<number, NumberingLevel>>();\n let numToAbstract = new Map<string, string>();\n if (numberingXml) {\n const parsed = parseNumbering(parser.parseFromString(numberingXml, 'application/xml'));\n abstractNums = parsed.abstractNums;\n numToAbstract = parsed.numToAbstract;\n }\n\n const relationships = relsXml\n ? parseRelationships(parser.parseFromString(relsXml, 'application/xml'))\n : new Map<string, string>();\n\n const images = await loadImages(zip, relationships);\n\n const comments = commentsXml\n ? parseComments(parser.parseFromString(commentsXml, 'application/xml'))\n : new Map<string, DocxComment>();\n\n const ctx: ConvertContext = {\n styles, abstractNums, numToAbstract, relationships, images,\n comments,\n activeCommentIds: new Set(),\n commentTextMap: new Map(),\n suggestionIdCounter: 1,\n };\n\n return { ctx, doc, zip };\n}\n\nfunction convertBody(doc: Document, ctx: ConvertContext): string {\n // Find body\n let body = doc.getElementsByTagNameNS(W_NS, 'body')[0];\n if (!body) {\n body = doc.querySelector('body') as Element;\n }\n if (!body) throw new Error('Invalid DOCX: no body element found');\n\n const children = Array.from(body.children);\n let html = '';\n let i = 0;\n\n while (i < children.length) {\n const el = children[i];\n\n if (el.localName === 'p') {\n // Check if it's a list paragraph\n if (isListParagraph(el)) {\n const result = convertListRun(children, i, ctx);\n html += result.html;\n i = result.nextIdx;\n continue;\n }\n\n // Check for blockquote\n if (isBlockquote(el, ctx)) {\n let bqContent = '';\n while (i < children.length && children[i].localName === 'p' && isBlockquote(children[i], ctx)) {\n bqContent += convertParagraph(children[i], ctx);\n i++;\n }\n html += `<blockquote>${bqContent}</blockquote>`;\n continue;\n }\n\n html += convertParagraph(el, ctx);\n } else if (el.localName === 'tbl') {\n html += convertTable(el, ctx);\n } else if (el.localName === 'ins') {\n // Body-level insertion (entire paragraphs inserted)\n const suggId = ctx.suggestionIdCounter++;\n const innerChildren = Array.from(el.children);\n let innerHtml = '';\n for (const ic of innerChildren) {\n if (ic.localName === 'p') innerHtml += convertParagraph(ic, ctx);\n else if (ic.localName === 'tbl') innerHtml += convertTable(ic, ctx);\n }\n // Wrap each paragraph-level insertion — mark is applied inline by Tiptap\n html += innerHtml ? `<div data-suggestion-insert=\"${suggId}\">${innerHtml}</div>` : '';\n } else if (el.localName === 'del') {\n // Body-level deletion (entire paragraphs deleted)\n const suggId = ctx.suggestionIdCounter++;\n const innerChildren = Array.from(el.children);\n let innerHtml = '';\n for (const ic of innerChildren) {\n if (ic.localName === 'p') innerHtml += convertParagraph(ic, ctx);\n }\n html += innerHtml ? `<div data-suggestion-delete=\"${suggId}\">${innerHtml}</div>` : '';\n }\n // Skip sectPr and other structural elements\n\n i++;\n }\n\n return html || '<p></p>';\n}\n\nexport async function docxToHtml(arrayBuffer: ArrayBuffer): Promise<string> {\n const { ctx, doc } = await buildContext(arrayBuffer);\n return convertBody(doc, ctx);\n}\n\n/**\n * Convert DOCX to HTML with annotation metadata (comments + tracked changes).\n * Comments are preserved as inline marks (<span data-comment-id=\"...\">) in the HTML,\n * and also returned as a structured array for the comments panel.\n */\nexport async function docxToHtmlWithAnnotations(arrayBuffer: ArrayBuffer): Promise<DocxAnnotationResult> {\n const { ctx, doc } = await buildContext(arrayBuffer);\n const html = convertBody(doc, ctx);\n\n // Build comments array from parsed comment metadata + accumulated selected text\n const comments: DocxAnnotationResult['comments'] = [];\n for (const [id, comment] of ctx.comments) {\n comments.push({\n id: `docx-comment-${id}`,\n author: { username: comment.author, isAI: false },\n text: comment.text,\n replies: [],\n resolved: false,\n severity: 'moderate',\n createdAt: comment.date || new Date().toISOString(),\n from: 0, // Accurate positions need editor context; marks handle visual placement\n to: 0,\n selectedText: ctx.commentTextMap.get(id) || '',\n });\n }\n\n return { html, comments };\n}\n\n// --- Highlight color mapping ---\n\nfunction highlightToHex(color: string | null): string | null {\n if (!color) return null;\n const map: Record<string, string> = {\n yellow: '#FFFF00',\n green: '#00FF00',\n cyan: '#00FFFF',\n magenta: '#FF00FF',\n blue: '#0000FF',\n red: '#FF0000',\n darkBlue: '#000080',\n darkCyan: '#008080',\n darkGreen: '#008000',\n darkMagenta: '#800080',\n darkRed: '#800000',\n darkYellow: '#808000',\n darkGray: '#808080',\n lightGray: '#C0C0C0',\n black: '#000000',\n white: '#FFFFFF',\n };\n return map[color] ?? null;\n}\n","import { Editor } from '@tiptap/react';\nimport {\n isSuggestChangesEnabled,\n enableSuggestChanges,\n disableSuggestChanges,\n} from '@blocknote/prosemirror-suggest-changes';\n\n/**\n * Apply an AI-generated text suggestion as a tracked change.\n * The suggestion appears as a reviewable change the user can accept/reject.\n *\n * Temporarily enables suggest-changes mode (if not already on), performs the\n * replacement, then restores the original mode. The dispatchTransaction wrapper\n * automatically converts the replacement into insertion/deletion marks.\n */\nexport function applyAISuggestion(\n editor: Editor,\n suggestion: {\n textToReplace: string;\n textReplacement: string;\n reason?: string;\n textBefore?: string;\n textAfter?: string;\n }\n): boolean {\n const { state, view } = editor;\n const { doc, schema } = state;\n\n // Find the text to replace in the document\n const docText = doc.textContent;\n let searchIndex = -1;\n\n // Try to locate using context (textBefore + textToReplace + textAfter)\n if (suggestion.textBefore || suggestion.textAfter) {\n const context = (suggestion.textBefore || '') + suggestion.textToReplace + (suggestion.textAfter || '');\n const contextIndex = docText.indexOf(context);\n if (contextIndex >= 0) {\n searchIndex = contextIndex + (suggestion.textBefore?.length || 0);\n }\n }\n\n // Fallback: direct search\n if (searchIndex < 0) {\n searchIndex = docText.indexOf(suggestion.textToReplace);\n }\n\n if (searchIndex < 0) return false;\n\n // Convert text offset to ProseMirror position by walking the doc\n let from = 0;\n let charCount = 0;\n let found = false;\n doc.descendants((node, pos) => {\n if (found) return false;\n if (node.isText) {\n const text = node.text || '';\n if (charCount + text.length > searchIndex) {\n from = pos + (searchIndex - charCount);\n found = true;\n return false;\n }\n charCount += text.length;\n }\n return true;\n });\n\n if (!found) return false;\n\n const to = from + suggestion.textToReplace.length;\n\n // Enable suggest-changes mode temporarily so the dispatch wrapper\n // converts this edit into insertion/deletion marks\n const wasEnabled = isSuggestChangesEnabled(view.state);\n if (!wasEnabled) {\n enableSuggestChanges(view.state, view.dispatch);\n }\n\n // Perform the replacement — the dispatch wrapper intercepts this\n // and transforms it into a suggestion transaction with marks\n const tr = view.state.tr.replaceWith(\n from,\n to,\n suggestion.textReplacement ? schema.text(suggestion.textReplacement) : []\n );\n view.dispatch(tr);\n\n // Restore previous mode\n if (!wasEnabled) {\n disableSuggestChanges(view.state, view.dispatch);\n }\n\n return true;\n}\n\n/**\n * Apply multiple AI suggestions to the document.\n * Applies them in order; each suggestion should have enough context\n * (textBefore/textAfter) to locate the correct position.\n */\nexport function applyAISuggestions(\n editor: Editor,\n suggestions: Array<{\n textToReplace: string;\n textReplacement: string;\n reason?: string;\n textBefore?: string;\n textAfter?: string;\n }>\n): { applied: number; failed: number } {\n let applied = 0;\n let failed = 0;\n\n for (const suggestion of suggestions) {\n const success = applyAISuggestion(editor, suggestion);\n if (success) {\n applied++;\n } else {\n failed++;\n }\n }\n\n return { applied, failed };\n}\n"],"mappings":"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","names":["import_react","import_react","import_lucide_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","import_jsx_runtime","ToolbarButton","import_react","import_lucide_react","import_lucide_react","import_jsx_runtime","import_react","import_lucide_react","import_jsx_runtime","React","import_jsx_runtime","import_react","import_lucide_react","import_jsx_runtime","import_react","import_lucide_react","import_jsx_runtime","timeAgo","import_react","import_lucide_react","import_jsx_runtime","remarkGfm","ReactMarkdown","import_core","import_prosemirror_suggest_changes","import_prosemirror_suggest_changes","import_core","import_core","import_state","tr","import_core","import_react","import_prosemirror_suggest_changes","import_react","import_react","import_ai","import_model","PMDOMParser","import_model","import_jsx_runtime","StarterKit","editor","React","import_lucide_react","import_jsx_runtime","styleDef","JSZip","import_prosemirror_suggest_changes"]}