import type { Editor } from "@tiptap/react" import { ensureMinimalTipTapDoc } from "@/lib/drive/richtext-content" export type DocsApplyAction = | { action: "insert_text"; text: string } | { action: "replace_selection"; text: string } | { action: "append_paragraph"; text: string } | { action: "set_content"; document: Record } export function parseDocsApplyPayload(raw: unknown): DocsApplyAction | null { if (!raw || typeof raw !== "object") return null const obj = raw as Record const action = obj.action if (action === "insert_text" && typeof obj.text === "string") { return { action, text: obj.text } } if (action === "replace_selection" && typeof obj.text === "string") { return { action, text: obj.text } } if (action === "append_paragraph" && typeof obj.text === "string") { return { action, text: obj.text } } if (action === "set_content" && obj.document && typeof obj.document === "object") { return { action, document: obj.document as Record, } } return null } /** Extrait un bloc ```ulti-docs-apply depuis une réponse assistant. */ export function extractDocsApplyFromMarkdown(text: string): DocsApplyAction | null { const match = text.match(/```ulti-docs-apply\s*([\s\S]*?)```/i) if (!match?.[1]) return null try { return parseDocsApplyPayload(JSON.parse(match[1].trim())) } catch { return null } } export function applyDocsAction(editor: Editor, cmd: DocsApplyAction): boolean { if (!editor.isEditable) return false switch (cmd.action) { case "insert_text": return editor.chain().focus().insertContent(cmd.text).run() case "replace_selection": if (editor.state.selection.empty) { return editor.chain().focus().insertContent(cmd.text).run() } return editor.chain().focus().deleteSelection().insertContent(cmd.text).run() case "append_paragraph": { const blocks = cmd.text .split(/\n{2,}/) .map((p) => p.trim()) .filter(Boolean) .map((p) => ({ type: "paragraph", content: [{ type: "text", text: p }], })) if (blocks.length === 0) return false return editor.chain().focus().insertContentAt(editor.state.doc.content.size, blocks).run() } case "set_content": { const doc = ensureMinimalTipTapDoc(cmd.document) return editor.commands.setContent(doc) } default: return false } }