claudaborative-editing 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -11
- package/dist/index.js +4177 -549
- package/dist/index.js.map +1 -1
- package/package.json +37 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/yjs/types.ts","../src/yjs/block-converter.ts","../src/yjs/document-manager.ts","../src/wordpress/api-client.ts","../src/wordpress/sync-client.ts","../src/wordpress/types.ts","../src/yjs/sync-protocol.ts","../src/blocks/parser.ts","../src/blocks/renderer.ts","../src/session/awareness.ts","../src/session/session-manager.ts","../src/tools/connect.ts","../src/tools/posts.ts","../src/tools/read.ts","../src/tools/edit.ts","../src/tools/status.ts","../src/server.ts","../src/cli/setup.ts","../src/index.ts"],"sourcesContent":["/**\n * Yjs document types matching the Gutenberg CRDT structure.\n *\n * Verified from @wordpress/sync and @wordpress/core-data source code.\n * The Y.Doc has two root Y.Maps: 'document' and 'state'.\n */\nimport * as Y from 'yjs';\n\n// --- Root-level keys ---\n\nexport const CRDT_RECORD_MAP_KEY = 'document';\nexport const CRDT_STATE_MAP_KEY = 'state';\nexport const CRDT_STATE_MAP_VERSION_KEY = 'version';\nexport const CRDT_STATE_MAP_SAVED_AT_KEY = 'savedAt';\nexport const CRDT_STATE_MAP_SAVED_BY_KEY = 'savedBy';\nexport const CRDT_DOC_VERSION = 1;\n\n// --- Block types ---\n\n/** Block attributes map: rich-text attributes are Y.Text, others are plain values. */\nexport type YBlockAttributes = Y.Map<Y.Text | unknown>;\n\n/** A block as represented in the Yjs document. */\nexport interface YBlockFields {\n name: string;\n clientId: string;\n attributes: YBlockAttributes;\n innerBlocks: Y.Array<Y.Map<unknown>>;\n isValid?: boolean;\n originalContent?: string;\n}\n\n/** A plain-object block for reading/writing (not Yjs types). */\nexport interface Block {\n name: string;\n clientId: string;\n attributes: Record<string, unknown>;\n innerBlocks: Block[];\n isValid?: boolean;\n originalContent?: string;\n}\n\n/**\n * Block attribute schema used to determine if an attribute is rich-text.\n * Since we don't have access to @wordpress/blocks' getBlockTypes() registry,\n * we maintain our own mapping of known rich-text attributes.\n */\nexport interface BlockAttributeSchema {\n type: 'rich-text' | 'string' | 'number' | 'boolean' | 'array' | 'object';\n role?: 'content' | 'local';\n}\n\n/**\n * Known rich-text attributes by block type.\n * This must be kept in sync with core block definitions.\n * When a block type is not in this map, all string attributes are treated as plain strings.\n */\nexport const RICH_TEXT_ATTRIBUTES: Record<string, Set<string>> = {\n 'core/paragraph': new Set(['content']),\n 'core/heading': new Set(['content']),\n 'core/list-item': new Set(['content']),\n 'core/quote': new Set(['value', 'citation']),\n 'core/pullquote': new Set(['value', 'citation']),\n 'core/verse': new Set(['content']),\n 'core/preformatted': new Set(['content']),\n 'core/freeform': new Set(['content']),\n 'core/button': new Set(['text']),\n 'core/table': new Set([]), // table cells use rich-text but are nested in body array\n 'core/footnotes': new Set(['content']),\n};\n\n/**\n * Default attribute values by block type.\n *\n * Gutenberg validates blocks against their schema and marks them as invalid\n * if expected attributes are missing. This map provides the default values\n * that Gutenberg would normally set when creating a block through the editor.\n */\nexport const DEFAULT_BLOCK_ATTRIBUTES: Record<string, Record<string, unknown>> = {\n 'core/paragraph': { dropCap: false },\n 'core/heading': { level: 2 },\n 'core/list': { ordered: false },\n};\n\n/**\n * Get default attributes for a block type.\n * Returns an empty object if no defaults are defined.\n */\nexport function getDefaultAttributes(blockName: string): Record<string, unknown> {\n return DEFAULT_BLOCK_ATTRIBUTES[blockName] ?? {};\n}\n\n/**\n * Check if a block attribute is rich-text typed.\n */\nexport function isRichTextAttribute(\n blockName: string,\n attributeName: string,\n): boolean {\n return RICH_TEXT_ATTRIBUTES[blockName]?.has(attributeName) ?? false;\n}\n\n// --- Post record in Y.Doc ---\n\n/**\n * The synced post properties stored in the 'document' Y.Map.\n * Title, content, excerpt are Y.Text. Blocks is Y.Array<Y.Map>.\n */\nexport const SYNCED_POST_PROPERTIES = new Set([\n 'author',\n 'blocks',\n 'content',\n 'comment_status',\n 'date',\n 'excerpt',\n 'featured_media',\n 'format',\n 'meta',\n 'ping_status',\n 'slug',\n 'status',\n 'sticky',\n 'tags',\n 'categories',\n 'template',\n 'title',\n]);\n\n// --- Collaborator awareness ---\n\nexport interface CollaboratorInfo {\n id: number;\n name: string;\n slug: string;\n avatar_urls: Record<string, string>;\n browserType: string;\n enteredAt: number;\n}\n\nexport interface AwarenessCursorPosition {\n relativePosition: {\n type: { client: number; clock: number };\n tname: null;\n item: null;\n assoc: number;\n };\n absoluteOffset: number;\n}\n\nexport interface AwarenessEditorState {\n selection:\n | { type: 'none' }\n | { type: 'cursor'; cursorPosition: AwarenessCursorPosition };\n}\n\nexport interface AwarenessLocalState {\n collaboratorInfo: CollaboratorInfo;\n editorState?: AwarenessEditorState;\n}\n","/**\n * Converts between plain Block objects and Yjs Y.Map types.\n *\n * Handles the mapping of rich-text attributes to Y.Text instances\n * based on the block type's known schema.\n */\nimport * as Y from 'yjs';\nimport { type Block, isRichTextAttribute } from './types.js';\n\n/**\n * Convert a plain Block object to a Y.Map suitable for insertion into the Y.Doc.\n *\n * Rich-text attributes (as determined by the block type) are stored as Y.Text.\n * All other attributes are stored as plain values.\n */\nexport function blockToYMap(block: Block): Y.Map<unknown> {\n const ymap = new Y.Map<unknown>();\n\n ymap.set('name', block.name);\n ymap.set('clientId', block.clientId);\n\n if (block.isValid !== undefined) {\n ymap.set('isValid', block.isValid);\n }\n if (block.originalContent !== undefined) {\n ymap.set('originalContent', block.originalContent);\n }\n\n // Attributes: rich-text ones become Y.Text, others stay as plain values\n const attrMap = new Y.Map<unknown>();\n if (block.attributes) {\n for (const [key, value] of Object.entries(block.attributes)) {\n if (isRichTextAttribute(block.name, key) && typeof value === 'string') {\n const ytext = new Y.Text();\n ytext.insert(0, value);\n attrMap.set(key, ytext);\n } else {\n attrMap.set(key, value);\n }\n }\n }\n ymap.set('attributes', attrMap);\n\n // Inner blocks: recurse\n const innerBlocksArray = new Y.Array<Y.Map<unknown>>();\n if (block.innerBlocks && block.innerBlocks.length > 0) {\n const innerMaps = block.innerBlocks.map((inner) => blockToYMap(inner));\n innerBlocksArray.push(innerMaps);\n }\n ymap.set('innerBlocks', innerBlocksArray);\n\n return ymap;\n}\n\n/**\n * Convert a Y.Map block from the Y.Doc to a plain Block object.\n *\n * Y.Text attributes are converted to their string representation.\n */\nexport function yMapToBlock(ymap: Y.Map<unknown>): Block {\n const name = ymap.get('name') as string;\n const clientId = ymap.get('clientId') as string;\n\n // Read attributes, converting Y.Text to strings\n const attrMap = ymap.get('attributes') as Y.Map<unknown> | undefined;\n const attributes: Record<string, unknown> = {};\n if (attrMap) {\n for (const [key, value] of attrMap.entries()) {\n if (value instanceof Y.Text) {\n attributes[key] = value.toString();\n } else {\n attributes[key] = value;\n }\n }\n }\n\n // Read inner blocks recursively\n const innerBlocksArray = ymap.get('innerBlocks') as\n | Y.Array<Y.Map<unknown>>\n | undefined;\n const innerBlocks: Block[] = [];\n if (innerBlocksArray) {\n for (let i = 0; i < innerBlocksArray.length; i++) {\n innerBlocks.push(yMapToBlock(innerBlocksArray.get(i)));\n }\n }\n\n const block: Block = {\n name,\n clientId,\n attributes,\n innerBlocks,\n };\n\n const isValid = ymap.get('isValid');\n if (isValid !== undefined) {\n block.isValid = isValid as boolean;\n }\n\n const originalContent = ymap.get('originalContent');\n if (originalContent !== undefined) {\n block.originalContent = originalContent as string;\n }\n\n return block;\n}\n\n/**\n * Update a Y.Text with a new string value using full replacement.\n *\n * WARNING: This uses delete-all + insert which targets specific CRDT items by ID.\n * In multi-client scenarios where the browser creates LOCAL Y.Text items alongside\n * REMOTE items (e.g. after `applyChangesToCRDTDoc`), the delete only removes our\n * items while the browser's survive — so the visible content doesn't change.\n *\n * For live collaborative editing, use `deltaUpdateYText()` instead.\n */\nexport function updateYText(ytext: Y.Text, newValue: string): void {\n if (ytext.length > 0) {\n ytext.delete(0, ytext.length);\n }\n if (newValue.length > 0) {\n ytext.insert(0, newValue);\n }\n}\n\n/**\n * Result of computing the delta between two strings.\n */\nexport interface TextDelta {\n prefixLen: number;\n deleteCount: number;\n insertText: string;\n}\n\n/**\n * Compute the minimal delta between two strings using common-prefix/common-suffix diff.\n * Returns null if the strings are identical.\n */\nexport function computeTextDelta(oldValue: string, newValue: string): TextDelta | null {\n if (oldValue === newValue) return null;\n\n // Find common prefix\n let prefixLen = 0;\n while (\n prefixLen < oldValue.length &&\n prefixLen < newValue.length &&\n oldValue[prefixLen] === newValue[prefixLen]\n ) {\n prefixLen++;\n }\n\n // Find common suffix (don't overlap with prefix)\n let suffixLen = 0;\n while (\n suffixLen < oldValue.length - prefixLen &&\n suffixLen < newValue.length - prefixLen &&\n oldValue[oldValue.length - 1 - suffixLen] ===\n newValue[newValue.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const deleteCount = oldValue.length - prefixLen - suffixLen;\n const insertText = newValue.slice(prefixLen, newValue.length - suffixLen);\n\n return { prefixLen, deleteCount, insertText };\n}\n\n/**\n * Update a Y.Text using delta-based editing via `Y.Text.applyDelta()`.\n *\n * Uses a simple common-prefix/common-suffix diff to compute the minimal\n * retain/delete/insert operations. Delta operations are POSITION-BASED,\n * not item-ID-based, so they operate on whatever CRDT items exist at\n * those positions — whether created by the browser or by us.\n *\n * This is the correct approach for live collaborative editing where\n * Gutenberg's `applyChangesToCRDTDoc` creates local items alongside\n * remote items in Y.Text.\n */\nexport function deltaUpdateYText(ytext: Y.Text, newValue: string): void {\n const oldValue = ytext.toString();\n const delta = computeTextDelta(oldValue, newValue);\n if (!delta) return;\n\n // Build delta ops\n const ops: Array<{ retain?: number; delete?: number; insert?: string }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n if (delta.deleteCount > 0) ops.push({ delete: delta.deleteCount });\n if (delta.insertText.length > 0) ops.push({ insert: delta.insertText });\n\n if (ops.length > 0) {\n ytext.applyDelta(ops);\n }\n}\n\n/**\n * Find the end position for an HTML-safe chunk of text.\n *\n * Given text and a starting offset, returns the end position for the next chunk,\n * ensuring it doesn't split inside an HTML tag. If the preferred end position\n * is inside a tag (between `<` and `>`), extends the chunk past the closing `>`.\n *\n * @param text The full text to chunk\n * @param offset The starting offset within the text\n * @param preferredSize The preferred chunk size in characters\n * @returns The end position (exclusive) for the chunk\n */\nexport function findHtmlSafeChunkEnd(text: string, offset: number, preferredSize: number): number {\n const end = Math.min(offset + preferredSize, text.length);\n if (end >= text.length) return text.length;\n\n // Check if we're inside an HTML tag at the proposed end position.\n // Scan backward from end to find the most recent '<' or '>' before the end.\n let inTag = false;\n for (let i = end - 1; i >= offset; i--) {\n if (text[i] === '>') {\n // We found a closing '>' before reaching any '<', so we're NOT inside a tag\n break;\n }\n if (text[i] === '<') {\n // We found an opening '<' without a closing '>' between it and end,\n // so the proposed end is inside a tag\n inTag = true;\n break;\n }\n }\n\n if (!inTag) return end;\n\n // Extend past the closing '>'\n const closingBracket = text.indexOf('>', end);\n if (closingBracket === -1) {\n // No closing bracket found — include the rest of the text\n return text.length;\n }\n return closingBracket + 1;\n}\n","/**\n * Manages Y.Doc lifecycle for WordPress post collaborative editing.\n *\n * Each Y.Doc mirrors the structure Gutenberg expects:\n * - Root map 'document': holds post fields (title, content, blocks, etc.)\n * - Root map 'state': holds sync metadata (version, savedAt, savedBy)\n */\nimport * as Y from 'yjs';\nimport {\n type Block,\n CRDT_DOC_VERSION,\n CRDT_RECORD_MAP_KEY,\n CRDT_STATE_MAP_KEY,\n CRDT_STATE_MAP_SAVED_AT_KEY,\n CRDT_STATE_MAP_SAVED_BY_KEY,\n CRDT_STATE_MAP_VERSION_KEY,\n isRichTextAttribute,\n} from './types.js';\nimport {\n blockToYMap,\n deltaUpdateYText,\n yMapToBlock,\n} from './block-converter.js';\n\nexport class DocumentManager {\n /**\n * Create a new Y.Doc initialized with Gutenberg's expected structure.\n */\n createDoc(): Y.Doc {\n const doc = new Y.Doc();\n\n doc.transact(() => {\n // Initialize state map only — matches Gutenberg's initializeYjsDoc.\n // Do NOT pre-populate the document map with empty Y.Text/Y.Array.\n // Those keys will be created on demand when content is first set,\n // or populated from a remote peer's state via sync.\n // Pre-creating them would cause CRDT merge conflicts during sync\n // (two competing values for the same Y.Map key).\n const stateMap = doc.getMap(CRDT_STATE_MAP_KEY);\n stateMap.set(CRDT_STATE_MAP_VERSION_KEY, CRDT_DOC_VERSION);\n });\n\n return doc;\n }\n\n /**\n * Get the root 'document' Y.Map.\n */\n getDocumentMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(CRDT_RECORD_MAP_KEY);\n }\n\n /**\n * Get the root 'state' Y.Map.\n */\n getStateMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(CRDT_STATE_MAP_KEY);\n }\n\n /**\n * Read the title as a plain string.\n */\n getTitle(doc: Y.Doc): string {\n const documentMap = this.getDocumentMap(doc);\n const title = documentMap.get('title');\n if (title instanceof Y.Text) {\n return title.toString();\n }\n return '';\n }\n\n /**\n * Set the title (replaces full Y.Text content).\n */\n setTitle(doc: Y.Doc, title: string): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const ytext = documentMap.get('title');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, title);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, title);\n documentMap.set('title', newYText);\n }\n });\n }\n\n /**\n * Get all blocks as plain Block[] objects.\n */\n getBlocks(doc: Y.Doc): Block[] {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as\n | Y.Array<Y.Map<unknown>>\n | undefined;\n if (!blocksArray) {\n return [];\n }\n\n const blocks: Block[] = [];\n for (let i = 0; i < blocksArray.length; i++) {\n blocks.push(yMapToBlock(blocksArray.get(i)));\n }\n return blocks;\n }\n\n /**\n * Set blocks from plain Block[] objects (replaces all existing blocks).\n */\n setBlocks(doc: Y.Doc, blocks: Block[]): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n let blocksArray = documentMap.get('blocks') as Y.Array<\n Y.Map<unknown>\n > | undefined;\n\n if (!blocksArray) {\n blocksArray = new Y.Array<Y.Map<unknown>>();\n documentMap.set('blocks', blocksArray);\n }\n\n // Clear existing blocks\n if (blocksArray.length > 0) {\n blocksArray.delete(0, blocksArray.length);\n }\n\n // Insert new blocks\n const ymaps = blocks.map((block) => blockToYMap(block));\n blocksArray.push(ymaps);\n });\n }\n\n /**\n * Get a single block by index. Supports dot notation for nested blocks\n * (e.g., \"2.1\" means inner block at index 1 of top-level block at index 2).\n */\n getBlockByIndex(doc: Y.Doc, index: string): Block | null {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n return null;\n }\n return yMapToBlock(ymap);\n }\n\n /**\n * Update a block's content and/or attributes at a given index.\n */\n updateBlock(\n doc: Y.Doc,\n index: string,\n changes: { content?: string; attributes?: Record<string, unknown> },\n ): void {\n doc.transact(() => {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n return;\n }\n\n const blockName = ymap.get('name') as string;\n const attrMap = ymap.get('attributes') as Y.Map<unknown>;\n\n if (changes.content !== undefined) {\n // 'content' is the primary rich-text attribute for most blocks\n if (isRichTextAttribute(blockName, 'content')) {\n const ytext = attrMap.get('content');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, changes.content);\n } else {\n // Create Y.Text if it doesn't exist yet\n const newYText = new Y.Text();\n newYText.insert(0, changes.content);\n attrMap.set('content', newYText);\n }\n } else {\n attrMap.set('content', changes.content);\n }\n }\n\n if (changes.attributes) {\n for (const [key, value] of Object.entries(changes.attributes)) {\n if (\n isRichTextAttribute(blockName, key) &&\n typeof value === 'string'\n ) {\n const existing = attrMap.get(key);\n if (existing instanceof Y.Text) {\n deltaUpdateYText(existing, value);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, value);\n attrMap.set(key, newYText);\n }\n } else {\n attrMap.set(key, value);\n }\n }\n }\n });\n }\n\n /**\n * Insert a block at the given position in the top-level blocks array.\n */\n insertBlock(doc: Y.Doc, position: number, block: Block): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n let blocksArray = documentMap.get('blocks') as Y.Array<\n Y.Map<unknown>\n > | undefined;\n if (!blocksArray) {\n blocksArray = new Y.Array<Y.Map<unknown>>();\n documentMap.set('blocks', blocksArray);\n }\n const ymap = blockToYMap(block);\n blocksArray.insert(position, [ymap]);\n });\n }\n\n /**\n * Remove `count` blocks starting at `startIndex`.\n */\n removeBlocks(doc: Y.Doc, startIndex: number, count: number): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<\n Y.Map<unknown>\n >;\n blocksArray.delete(startIndex, count);\n });\n }\n\n /**\n * Insert a block as an inner block of a parent block.\n */\n insertInnerBlock(doc: Y.Doc, parentIndex: string, position: number, block: Block): void {\n doc.transact(() => {\n const parentYMap = this._resolveBlockYMap(doc, parentIndex);\n if (!parentYMap) {\n throw new Error(`Block not found at index ${parentIndex}`);\n }\n\n let innerBlocksArray = parentYMap.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!innerBlocksArray) {\n innerBlocksArray = new Y.Array<Y.Map<unknown>>();\n parentYMap.set('innerBlocks', innerBlocksArray);\n }\n\n const ymap = blockToYMap(block);\n innerBlocksArray.insert(position, [ymap]);\n });\n }\n\n /**\n * Remove inner blocks from a parent block.\n */\n removeInnerBlocks(doc: Y.Doc, parentIndex: string, startIndex: number, count: number): void {\n doc.transact(() => {\n const parentYMap = this._resolveBlockYMap(doc, parentIndex);\n if (!parentYMap) {\n throw new Error(`Block not found at index ${parentIndex}`);\n }\n\n const innerBlocksArray = parentYMap.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!innerBlocksArray) {\n throw new Error(`Block at ${parentIndex} has no inner blocks`);\n }\n\n innerBlocksArray.delete(startIndex, count);\n });\n }\n\n /**\n * Move a block from one position to another.\n */\n moveBlock(doc: Y.Doc, fromIndex: number, toIndex: number): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<\n Y.Map<unknown>\n >;\n\n // Read the block at fromIndex as a plain object, then re-insert\n const block = yMapToBlock(blocksArray.get(fromIndex));\n blocksArray.delete(fromIndex, 1);\n\n // Adjust target index if removing shifts it\n const adjustedIndex = fromIndex < toIndex ? toIndex - 1 : toIndex;\n const ymap = blockToYMap(block);\n blocksArray.insert(adjustedIndex, [ymap]);\n });\n }\n\n /**\n * Mark the document as saved by updating the state map.\n */\n markSaved(doc: Y.Doc): void {\n doc.transact(() => {\n const stateMap = this.getStateMap(doc);\n stateMap.set(CRDT_STATE_MAP_SAVED_AT_KEY, Date.now());\n stateMap.set(CRDT_STATE_MAP_SAVED_BY_KEY, doc.clientID);\n });\n }\n\n /**\n * Get the content field as a string.\n */\n getContent(doc: Y.Doc): string {\n const documentMap = this.getDocumentMap(doc);\n const content = documentMap.get('content');\n if (content instanceof Y.Text) {\n return content.toString();\n }\n return '';\n }\n\n /**\n * Set the content field.\n */\n setContent(doc: Y.Doc, content: string): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const ytext = documentMap.get('content');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, content);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, content);\n documentMap.set('content', newYText);\n }\n });\n }\n\n /**\n * Get a post property from the document map.\n */\n getProperty(doc: Y.Doc, key: string): unknown {\n const documentMap = this.getDocumentMap(doc);\n const value = documentMap.get(key);\n if (value instanceof Y.Text) {\n return value.toString();\n }\n return value;\n }\n\n /**\n * Set a post property in the document map.\n */\n setProperty(doc: Y.Doc, key: string, value: unknown): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const existing = documentMap.get(key);\n if (existing instanceof Y.Text && typeof value === 'string') {\n deltaUpdateYText(existing, value);\n } else {\n documentMap.set(key, value);\n }\n });\n }\n\n /**\n * Get the raw Y.Text for a block attribute.\n * Returns null if the block doesn't exist, the attribute doesn't exist,\n * or the attribute is not a Y.Text (i.e., not a rich-text attribute).\n */\n getBlockAttributeYText(doc: Y.Doc, index: string, attrName: string): Y.Text | null {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) return null;\n const attrMap = ymap.get('attributes') as Y.Map<unknown> | undefined;\n if (!attrMap) return null;\n const attr = attrMap.get(attrName);\n return attr instanceof Y.Text ? attr : null;\n }\n\n /**\n * Get the raw Y.Text for a block's content attribute.\n * Returns null if the block or content attribute doesn't exist.\n */\n getBlockContentYText(doc: Y.Doc, index: string): Y.Text | null {\n return this.getBlockAttributeYText(doc, index, 'content');\n }\n\n /**\n * Resolve a dot-notation index to a Y.Map block reference.\n * E.g., \"2\" → top-level block 2, \"2.1\" → inner block 1 of block 2.\n */\n private _resolveBlockYMap(\n doc: Y.Doc,\n index: string,\n ): Y.Map<unknown> | null {\n const parts = index.split('.').map(Number);\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<\n Y.Map<unknown>\n >;\n\n if (parts.length === 0 || isNaN(parts[0])) {\n return null;\n }\n\n let current: Y.Map<unknown> | null = null;\n let currentArray: Y.Array<Y.Map<unknown>> = blocksArray;\n\n for (const part of parts) {\n if (part < 0 || part >= currentArray.length) {\n return null;\n }\n current = currentArray.get(part);\n // For next iteration, if there are more parts, descend into innerBlocks\n const innerBlocks = current.get('innerBlocks') as\n | Y.Array<Y.Map<unknown>>\n | undefined;\n if (innerBlocks) {\n currentArray = innerBlocks;\n }\n }\n\n return current;\n }\n}\n","import type {\n WordPressConfig,\n WPPost,\n WPUser,\n SyncPayload,\n SyncResponse,\n} from './types.js';\n\n/**\n * WordPress REST API client using Application Password (HTTP Basic Auth).\n *\n * Uses native fetch() — requires Node.js 18+.\n */\nexport class WordPressApiClient {\n private baseUrl: string;\n private authHeader: string;\n\n constructor(config: WordPressConfig) {\n // Normalize URL: strip trailing slash(es)\n const siteUrl = config.siteUrl.replace(/\\/+$/, '');\n this.baseUrl = `${siteUrl}/wp-json`;\n this.authHeader = `Basic ${btoa(config.username + ':' + config.appPassword)}`;\n }\n\n /**\n * Validate the connection by fetching the current user.\n * Tests both auth and API availability.\n */\n async validateConnection(): Promise<WPUser> {\n return this.getCurrentUser();\n }\n\n /**\n * Check that the sync endpoint exists.\n * POSTs an empty rooms array to verify the endpoint responds.\n */\n async validateSyncEndpoint(): Promise<void> {\n await this.sendSyncUpdate({ rooms: [] });\n }\n\n /**\n * Get the current authenticated user.\n * GET /wp/v2/users/me\n */\n async getCurrentUser(): Promise<WPUser> {\n return this.apiFetch<WPUser>('/wp/v2/users/me');\n }\n\n /**\n * List posts with optional filters.\n * GET /wp/v2/posts?status=...&search=...&per_page=...&context=edit\n */\n async listPosts(options?: {\n status?: string;\n search?: string;\n perPage?: number;\n }): Promise<WPPost[]> {\n const params = new URLSearchParams({ context: 'edit' });\n\n if (options?.status) {\n params.set('status', options.status);\n }\n if (options?.search) {\n params.set('search', options.search);\n }\n if (options?.perPage !== undefined) {\n params.set('per_page', String(options.perPage));\n }\n\n return this.apiFetch<WPPost[]>(`/wp/v2/posts?${params.toString()}`);\n }\n\n /**\n * Get a single post by ID.\n * GET /wp/v2/posts/{id}?context=edit\n */\n async getPost(id: number): Promise<WPPost> {\n return this.apiFetch<WPPost>(`/wp/v2/posts/${id}?context=edit`);\n }\n\n /**\n * Create a new post.\n * POST /wp/v2/posts\n */\n async createPost(data: {\n title?: string;\n content?: string;\n status?: string;\n }): Promise<WPPost> {\n return this.apiFetch<WPPost>('/wp/v2/posts', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n /**\n * Send a sync payload and receive response.\n * POST /wp-sync/v1/updates\n */\n async sendSyncUpdate(payload: SyncPayload): Promise<SyncResponse> {\n return this.apiFetch<SyncResponse>('/wp-sync/v1/updates', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n }\n\n /**\n * Produce a human-friendly error message for common failure modes.\n */\n private formatErrorMessage(path: string, status: number, body: string): string {\n if (status === 401 || status === 403) {\n return `Authentication failed. Check your username and Application Password. (HTTP ${status})`;\n }\n\n if (status === 404 && path.startsWith('/wp-sync/')) {\n return (\n 'Collaborative editing is not enabled. ' +\n 'Enable it in Settings \\u2192 Writing in your WordPress admin, then try again. ' +\n '(Requires WordPress 7.0 or later.)'\n );\n }\n\n return `WordPress API error ${status}: ${body}`;\n }\n\n /**\n * Internal fetch helper with auth and error handling.\n */\n private async apiFetch<T>(path: string, options?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: this.authHeader,\n Accept: 'application/json',\n };\n\n // Add Content-Type for requests with a body\n if (options?.method === 'POST' || options?.method === 'PUT') {\n headers['Content-Type'] = 'application/json';\n }\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...headers,\n ...(options?.headers as Record<string, string> | undefined),\n },\n });\n\n if (!response.ok) {\n let errorBody: string;\n try {\n errorBody = await response.text();\n } catch {\n errorBody = '(unable to read response body)';\n }\n\n const message = this.formatErrorMessage(path, response.status, errorBody);\n\n throw new WordPressApiError(\n message,\n response.status,\n errorBody,\n );\n }\n\n return (await response.json()) as T;\n }\n}\n\n/**\n * Custom error class for WordPress API errors,\n * carrying the HTTP status and response body.\n */\nexport class WordPressApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: string,\n ) {\n super(message);\n this.name = 'WordPressApiError';\n }\n}\n","import type {\n SyncUpdate,\n SyncClientConfig,\n SyncUpdateType,\n AwarenessState,\n LocalAwarenessState,\n} from './types.js';\nimport type { WordPressApiClient } from './api-client.js';\n\nexport type SyncStatus = 'connecting' | 'connected' | 'disconnected' | 'error';\n\nexport interface SyncCallbacks {\n /** Process an incoming update. Return a SyncUpdate to queue (e.g. sync_step2), or null. */\n onUpdate: (update: SyncUpdate) => SyncUpdate | null;\n /** Called when awareness state changes. */\n onAwareness: (state: AwarenessState) => void;\n /** Called when connection status changes. */\n onStatusChange: (status: SyncStatus) => void;\n /** Called when the server requests compaction; must return a compaction update. */\n onCompactionRequested: () => SyncUpdate;\n /** Return the current local awareness state, or null if disconnected. */\n getAwarenessState: () => LocalAwarenessState;\n}\n\n/**\n * HTTP polling sync client that maintains the Gutenberg sync loop.\n *\n * Uses chained setTimeout (not setInterval) so polling interval\n * can adapt dynamically to collaborator presence and errors.\n */\nexport class SyncClient {\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private endCursor: number = 0;\n private updateQueue: SyncUpdate[] = [];\n private queuePaused: boolean = true;\n private hasCollaborators: boolean = false;\n private currentBackoff: number;\n private isPolling: boolean = false;\n private pollInProgress: boolean = false;\n private flushRequested: boolean = false;\n private room: string = '';\n private clientId: number = 0;\n\n private callbacks: SyncCallbacks | null = null;\n private firstPollResolve: (() => void) | null = null;\n\n constructor(\n private apiClient: WordPressApiClient,\n private config: SyncClientConfig,\n ) {\n this.currentBackoff = config.pollingInterval;\n }\n\n /**\n * Returns a promise that resolves after the first poll cycle completes.\n * Used to wait for initial sync state before loading content.\n */\n waitForFirstPoll(): Promise<void> {\n return new Promise<void>((resolve) => {\n this.firstPollResolve = resolve;\n });\n }\n\n /**\n * Start the polling loop for a room.\n *\n * @param room Room identifier, e.g. 'postType/post:123'\n * @param clientId Y.Doc clientID\n * @param initialUpdates Initial sync updates to send (sync_step1)\n * @param callbacks Event callbacks\n */\n start(\n room: string,\n clientId: number,\n initialUpdates: SyncUpdate[],\n callbacks: SyncCallbacks,\n ): void {\n this.room = room;\n this.clientId = clientId;\n this.callbacks = callbacks;\n this.endCursor = 0;\n this.queuePaused = true;\n this.hasCollaborators = false;\n this.currentBackoff = this.config.pollingInterval;\n this.isPolling = true;\n\n // Seed queue with initial updates (e.g. sync_step1)\n this.updateQueue = [...initialUpdates];\n\n this.callbacks.onStatusChange('connecting');\n\n // Kick off the first poll immediately\n this.pollTimer = setTimeout(() => this.poll(), 0);\n }\n\n /**\n * Stop the polling loop.\n */\n stop(): void {\n this.isPolling = false;\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.callbacks?.onStatusChange('disconnected');\n this.callbacks = null;\n }\n\n /**\n * Flush the outgoing queue by triggering an immediate poll.\n *\n * If a poll is already in progress, sets a flag so that another poll\n * is triggered immediately after the current one completes. This avoids\n * concurrent poll execution while ensuring the flush is honoured.\n */\n flushQueue(): void {\n if (!this.isPolling) return;\n\n if (this.pollInProgress) {\n // A poll is already running — request a follow-up poll when it finishes\n this.flushRequested = true;\n return;\n }\n\n // Cancel the scheduled timer and poll immediately\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.pollTimer = setTimeout(() => this.poll(), 0);\n }\n\n /**\n * Add an update to the outgoing queue.\n */\n queueUpdate(update: SyncUpdate): void {\n this.updateQueue.push(update);\n }\n\n /**\n * Get sync status info.\n */\n getStatus(): {\n isPolling: boolean;\n hasCollaborators: boolean;\n queuePaused: boolean;\n endCursor: number;\n queueSize: number;\n } {\n return {\n isPolling: this.isPolling,\n hasCollaborators: this.hasCollaborators,\n queuePaused: this.queuePaused,\n endCursor: this.endCursor,\n queueSize: this.updateQueue.length,\n };\n }\n\n /**\n * Execute one poll cycle.\n */\n private async poll(): Promise<void> {\n if (!this.isPolling || !this.callbacks) {\n return;\n }\n\n // Re-entrancy guard: if a poll is already running, skip\n if (this.pollInProgress) {\n return;\n }\n\n this.pollInProgress = true;\n this.flushRequested = false;\n\n // Drain the queue: take all pending updates.\n // When paused, only initial/sync updates are sent (queue is drained regardless);\n // the distinction is that new edits are only queued when unpaused.\n const updates = this.updateQueue.splice(0);\n\n const awareness = this.callbacks.getAwarenessState();\n\n try {\n const payload = {\n rooms: [\n {\n room: this.room,\n client_id: this.clientId,\n after: this.endCursor,\n awareness,\n updates,\n },\n ],\n };\n\n const response = await this.apiClient.sendSyncUpdate(payload);\n\n // Success — reset backoff\n this.currentBackoff = this.hasCollaborators\n ? this.config.pollingIntervalWithCollaborators\n : this.config.pollingInterval;\n\n this.callbacks.onStatusChange('connected');\n\n this.processResponse(response);\n\n // Resolve the first-poll promise after processing the response\n if (this.firstPollResolve) {\n this.firstPollResolve();\n this.firstPollResolve = null;\n }\n } catch (error) {\n // Restore un-sent updates to front of queue,\n // excluding compaction updates (which are stale after an error).\n const restorable = updates.filter(\n (u) => (u.type as SyncUpdateType) !== ('compaction' as SyncUpdateType),\n );\n this.updateQueue.unshift(...restorable);\n\n this.callbacks.onStatusChange('error');\n\n // Exponential backoff: double current, cap at max\n this.currentBackoff = Math.min(\n this.currentBackoff * 2,\n this.config.maxErrorBackoff,\n );\n }\n\n this.pollInProgress = false;\n\n // If a flush was requested during this poll, trigger an immediate follow-up\n if (this.flushRequested) {\n this.flushRequested = false;\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.pollTimer = setTimeout(() => this.poll(), 0);\n } else {\n this.scheduleNextPoll();\n }\n }\n\n /**\n * Schedule the next poll using the current interval / backoff.\n */\n private scheduleNextPoll(): void {\n if (!this.isPolling) {\n return;\n }\n\n this.pollTimer = setTimeout(() => this.poll(), this.currentBackoff);\n }\n\n /**\n * Process a sync response from the server.\n */\n private processResponse(response: { rooms: Array<{\n room: string;\n end_cursor: number;\n awareness: AwarenessState;\n updates: SyncUpdate[];\n should_compact?: boolean;\n }> }): void {\n if (!this.callbacks) {\n return;\n }\n\n const roomData = response.rooms.find((r) => r.room === this.room);\n if (!roomData) {\n return;\n }\n\n // 1. Update end cursor\n this.endCursor = roomData.end_cursor;\n\n // 2. Process awareness — detect collaborators\n this.callbacks.onAwareness(roomData.awareness);\n\n const otherClients = Object.keys(roomData.awareness).filter(\n (id) => Number(id) !== this.clientId && roomData.awareness[id] !== null,\n );\n const hadCollaborators = this.hasCollaborators;\n this.hasCollaborators = otherClients.length > 0;\n\n // If we just gained collaborators, unpause the queue\n if (this.hasCollaborators && !hadCollaborators) {\n this.queuePaused = false;\n }\n\n // Adjust backoff/interval for collaborator presence\n this.currentBackoff = this.hasCollaborators\n ? this.config.pollingIntervalWithCollaborators\n : this.config.pollingInterval;\n\n // 3. Process incoming updates\n for (const update of roomData.updates) {\n const reply = this.callbacks.onUpdate(update);\n if (reply) {\n this.updateQueue.push(reply);\n }\n }\n\n // 4. Handle compaction request\n if (roomData.should_compact) {\n const compactionUpdate = this.callbacks.onCompactionRequested();\n this.updateQueue.push(compactionUpdate);\n }\n }\n}\n","/**\n * WordPress REST API and sync protocol types.\n *\n * These types match the wire format used by the Gutenberg HTTP polling\n * sync provider at POST /wp-sync/v1/updates.\n */\n\n// --- Sync Protocol Types ---\n\nexport enum SyncUpdateType {\n SYNC_STEP_1 = 'sync_step1',\n SYNC_STEP_2 = 'sync_step2',\n UPDATE = 'update',\n COMPACTION = 'compaction',\n}\n\n/** A single typed update with base64-encoded Yjs binary data. */\nexport interface SyncUpdate {\n type: SyncUpdateType;\n data: string; // base64-encoded Yjs V2 update\n}\n\n/** Awareness state: null means disconnected. */\nexport type LocalAwarenessState = object | null;\n\n/** Server-side awareness: map of clientId (as string) → state object. */\nexport type AwarenessState = Record<string, LocalAwarenessState>;\n\n// --- Client → Server ---\n\nexport interface SyncEnvelopeFromClient {\n room: string;\n client_id: number;\n after: number;\n awareness: LocalAwarenessState;\n updates: SyncUpdate[];\n}\n\nexport interface SyncPayload {\n rooms: SyncEnvelopeFromClient[];\n}\n\n// --- Server → Client ---\n\nexport interface SyncEnvelopeFromServer {\n room: string;\n end_cursor: number;\n awareness: AwarenessState;\n updates: SyncUpdate[];\n should_compact?: boolean;\n compaction_request?: SyncUpdate[]; // deprecated\n}\n\nexport interface SyncResponse {\n rooms: SyncEnvelopeFromServer[];\n}\n\n// --- WordPress REST API Types ---\n\n/** WordPress post as returned by the REST API (subset of fields we care about). */\nexport interface WPPost {\n id: number;\n title: { rendered: string; raw?: string };\n content: { rendered: string; raw?: string };\n excerpt: { rendered: string; raw?: string };\n status: string;\n type: string;\n slug: string;\n author: number;\n date: string | null;\n modified: string;\n categories?: number[];\n tags?: number[];\n meta?: Record<string, unknown>;\n}\n\n/** WordPress user as returned by /wp/v2/users/me. */\nexport interface WPUser {\n id: number;\n name: string;\n slug: string;\n avatar_urls: Record<string, string>;\n}\n\n// --- Connection Config ---\n\nexport interface WordPressConfig {\n siteUrl: string;\n username: string;\n appPassword: string;\n}\n\n// --- Sync Client Config ---\n\nexport interface SyncClientConfig {\n /** Polling interval in ms when editing solo. */\n pollingInterval: number;\n /** Polling interval in ms when collaborators are present. */\n pollingIntervalWithCollaborators: number;\n /** Max exponential backoff in ms on error. */\n maxErrorBackoff: number;\n}\n\nexport const DEFAULT_SYNC_CONFIG: SyncClientConfig = {\n pollingInterval: 1000,\n pollingIntervalWithCollaborators: 250,\n maxErrorBackoff: 30_000,\n};\n","/**\n * Yjs sync protocol helpers for the HTTP polling transport.\n *\n * Sync steps (step1/step2) use y-protocols' standard encoding.\n * Regular updates and compactions use Yjs V1 encoding (matching Gutenberg).\n * All binary data is base64-encoded for transport.\n */\nimport * as Y from 'yjs';\nimport * as syncProtocol from 'y-protocols/sync';\nimport * as encoding from 'lib0/encoding';\nimport * as decoding from 'lib0/decoding';\nimport { type SyncUpdate, SyncUpdateType } from '../wordpress/types.js';\n\n/**\n * Create a sync_step1 message announcing our state vector.\n */\nexport function createSyncStep1(doc: Y.Doc): SyncUpdate {\n const encoder = encoding.createEncoder();\n syncProtocol.writeSyncStep1(encoder, doc);\n const data = encoding.toUint8Array(encoder);\n\n return {\n type: SyncUpdateType.SYNC_STEP_1,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Process an incoming sync_step1 and create a sync_step2 response.\n *\n * Reads the remote state vector from the step1 message and encodes\n * the missing updates as a step2 reply.\n */\nexport function createSyncStep2(\n doc: Y.Doc,\n step1Data: Uint8Array,\n): SyncUpdate {\n const decoder = decoding.createDecoder(step1Data);\n const encoder = encoding.createEncoder();\n\n // readSyncMessage reads the message type byte and the state vector,\n // then writes the appropriate response (step2) into the encoder.\n syncProtocol.readSyncMessage(decoder, encoder, doc, 'sync');\n\n const data = encoding.toUint8Array(encoder);\n\n return {\n type: SyncUpdateType.SYNC_STEP_2,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Process an incoming sync update.\n *\n * For SYNC_STEP_1: generates a SYNC_STEP_2 response.\n * For SYNC_STEP_2: applies the update via y-protocols and returns null.\n * For UPDATE / COMPACTION: applies the V1 update and returns null.\n *\n * Returns a response SyncUpdate if one is needed (e.g., step2 reply),\n * or null if no response is required.\n */\nexport function processIncomingUpdate(\n doc: Y.Doc,\n update: SyncUpdate,\n): SyncUpdate | null {\n const rawData = base64ToUint8Array(update.data);\n\n switch (update.type) {\n case SyncUpdateType.SYNC_STEP_1: {\n // Respond with step2\n return createSyncStep2(doc, rawData);\n }\n\n case SyncUpdateType.SYNC_STEP_2: {\n // Apply step2 via y-protocols decoder\n const decoder = decoding.createDecoder(rawData);\n const encoder = encoding.createEncoder();\n syncProtocol.readSyncMessage(decoder, encoder, doc, 'sync');\n // step2 processing doesn't produce a response\n return null;\n }\n\n case SyncUpdateType.UPDATE:\n case SyncUpdateType.COMPACTION: {\n // Apply V1 update directly (Gutenberg uses V1 encoding for updates)\n Y.applyUpdate(doc, rawData, 'remote');\n return null;\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Create an update message from a Y.Doc change (V1 encoded).\n */\nexport function createUpdateFromChange(update: Uint8Array): SyncUpdate {\n return {\n type: SyncUpdateType.UPDATE,\n data: uint8ArrayToBase64(update),\n };\n}\n\n/**\n * Create a compaction update containing the full document state (V1 encoded).\n */\nexport function createCompactionUpdate(doc: Y.Doc): SyncUpdate {\n const data = Y.encodeStateAsUpdate(doc);\n return {\n type: SyncUpdateType.COMPACTION,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Encode a Uint8Array to a base64 string.\n */\nexport function uint8ArrayToBase64(data: Uint8Array): string {\n return Buffer.from(data).toString('base64');\n}\n\n/**\n * Decode a base64 string to a Uint8Array.\n */\nexport function base64ToUint8Array(base64: string): Uint8Array {\n return new Uint8Array(Buffer.from(base64, 'base64'));\n}\n","/**\n * Block parser: wraps @wordpress/block-serialization-default-parser to produce\n * normalized ParsedBlock[] from Gutenberg HTML, then converts to Block[].\n */\n\nimport { parse as wpParse } from '@wordpress/block-serialization-default-parser';\nimport type { RawParsedBlock, ParsedBlock } from './types.js';\nimport type { Block } from '../yjs/types.js';\n\n/**\n * Parse Gutenberg HTML content into normalized blocks.\n * - Null blockNames (freeform HTML) become 'core/freeform'\n * - Attributes are extracted from the block comment delimiters (attrs field)\n * - innerHTML is preserved as originalContent\n * - For common blocks, extract text content from innerHTML into attributes\n */\nexport function parseBlocks(html: string): ParsedBlock[] {\n const raw = wpParse(html) as RawParsedBlock[];\n return raw\n .filter((block) => block.blockName !== null || block.innerHTML.trim() !== '')\n .map(normalizeParsedBlock);\n}\n\n/**\n * Convert a ParsedBlock to a Block (adding clientId, mapping innerBlocks).\n */\nexport function parsedBlockToBlock(parsed: ParsedBlock): Block {\n return {\n name: parsed.name,\n clientId: crypto.randomUUID(),\n attributes: { ...parsed.attributes },\n innerBlocks: parsed.innerBlocks.map(parsedBlockToBlock),\n originalContent: parsed.originalContent,\n };\n}\n\nfunction normalizeParsedBlock(raw: RawParsedBlock): ParsedBlock {\n const blockName = raw.blockName ?? 'core/freeform';\n const commentAttrs = raw.attrs ?? {};\n const extractedAttrs = extractAttributesFromHTML(\n blockName,\n raw.innerHTML,\n commentAttrs,\n );\n\n return {\n name: blockName,\n attributes: { ...commentAttrs, ...extractedAttrs },\n innerBlocks: raw.innerBlocks\n .filter(\n (block) => block.blockName !== null || block.innerHTML.trim() !== '',\n )\n .map(normalizeParsedBlock),\n originalContent: raw.innerHTML,\n };\n}\n\n/**\n * Extract content/text attributes from a block's innerHTML.\n * For core/paragraph: extract text between <p> tags -> attributes.content\n * For core/heading: extract text between <h1>-<h6> tags -> attributes.content\n * For core/list-item: extract text between <li> tags -> attributes.content\n * For core/image: extract src, alt from <img> tag -> attributes.url, attributes.alt\n * For core/button: extract text from <a> tag -> attributes.text\n */\nfunction extractAttributesFromHTML(\n blockName: string,\n innerHTML: string,\n attrs: Record<string, unknown>,\n): Record<string, unknown> {\n const extracted: Record<string, unknown> = {};\n\n switch (blockName) {\n case 'core/paragraph': {\n const match = innerHTML.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n break;\n }\n case 'core/heading': {\n const match = innerHTML.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n // Preserve the level from comment attrs if present\n if (attrs.level !== undefined) {\n extracted.level = attrs.level;\n }\n break;\n }\n case 'core/list-item': {\n const match = innerHTML.match(/<li[^>]*>([\\s\\S]*?)<\\/li>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n break;\n }\n case 'core/image': {\n const imgMatch = innerHTML.match(/<img[^>]*>/);\n if (imgMatch) {\n const srcMatch = imgMatch[0].match(/src=\"([^\"]*)\"/);\n if (srcMatch) {\n extracted.url = srcMatch[1];\n }\n const altMatch = imgMatch[0].match(/alt=\"([^\"]*)\"/);\n if (altMatch) {\n extracted.alt = altMatch[1];\n }\n }\n break;\n }\n case 'core/button': {\n const match = innerHTML.match(/<a[^>]*>([\\s\\S]*?)<\\/a>/);\n if (match) {\n extracted.text = match[1].trim();\n }\n // Also extract the href as url\n const hrefMatch = innerHTML.match(/<a[^>]*href=\"([^\"]*)\"[^>]*>/);\n if (hrefMatch) {\n extracted.url = hrefMatch[1];\n }\n break;\n }\n }\n\n return extracted;\n}\n","/**\n * Block renderer: converts Block[] to Claude-friendly text representation.\n */\n\nimport type { Block } from '../yjs/types.js';\n\n/**\n * Render a post's blocks as Claude-friendly text.\n *\n * Output format:\n * Title: \"Post Title Here\"\n *\n * [0] core/heading (level=2)\n * \"What Are Widgets?\"\n *\n * [1] core/paragraph\n * \"Widgets are fundamental building blocks...\"\n */\nexport function renderPost(title: string, blocks: Block[]): string {\n const parts: string[] = [];\n parts.push(`Title: \"${title}\"`);\n\n if (blocks.length > 0) {\n parts.push('');\n parts.push(renderBlockList(blocks));\n }\n\n return parts.join('\\n');\n}\n\n/**\n * Render a single block with its details.\n */\nexport function renderBlock(block: Block, index: string): string {\n const displayAttrs = getDisplayAttributes(block);\n const attrStr = Object.entries(displayAttrs)\n .map(([k, v]) => `${k}=${typeof v === 'string' ? `\"${v}\"` : v}`)\n .join(', ');\n\n const header = attrStr\n ? `[${index}] ${block.name} (${attrStr})`\n : `[${index}] ${block.name}`;\n\n const lines: string[] = [header];\n\n const textContent = getBlockTextContent(block);\n if (textContent) {\n lines.push(` \"${textContent}\"`);\n }\n\n if (block.innerBlocks.length > 0) {\n const innerRendered = renderBlockList(block.innerBlocks, index, 1);\n lines.push(innerRendered);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render blocks as a list with indices.\n * @param blocks - The blocks to render\n * @param parentIndex - Parent index prefix for nested blocks (e.g., \"2\" -> \"2.0\", \"2.1\")\n * @param indent - Current indentation level\n */\nfunction renderBlockList(\n blocks: Block[],\n parentIndex?: string,\n indent: number = 0,\n): string {\n const indentStr = ' '.repeat(indent);\n\n return blocks\n .map((block, i) => {\n const index =\n parentIndex !== undefined ? `${parentIndex}.${i}` : String(i);\n const rendered = renderBlock(block, index);\n // Indent each line of the rendered block\n if (indent > 0) {\n return rendered\n .split('\\n')\n .map((line) => indentStr + line)\n .join('\\n');\n }\n return rendered;\n })\n .join('\\n\\n');\n}\n\n/**\n * Get the primary text content of a block from its attributes.\n * Checks 'content' first, then 'text', then 'value', then 'citation'.\n */\nfunction getBlockTextContent(block: Block): string {\n for (const key of ['content', 'text', 'value', 'citation']) {\n const val = block.attributes[key];\n if (typeof val === 'string' && val.length > 0) {\n return val;\n }\n }\n return '';\n}\n\n/**\n * Get display-worthy attributes (non-content attributes that are useful to show).\n * For headings: show level\n * For images: show url, alt\n * For buttons: show url\n * For columns: show verticalAlignment\n * Skip 'content', 'text', 'value' (shown separately as text content)\n * Skip complex objects/arrays\n */\nfunction getDisplayAttributes(\n block: Block,\n): Record<string, string | number | boolean> {\n const skipKeys = new Set(['content', 'text', 'value', 'citation']);\n const result: Record<string, string | number | boolean> = {};\n\n for (const [key, val] of Object.entries(block.attributes)) {\n if (skipKeys.has(key)) continue;\n if (\n typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean'\n ) {\n result[key] = val;\n }\n }\n\n return result;\n}\n","/**\n * Awareness protocol helpers for Claude's presence in collaborative editing.\n *\n * Builds the local awareness state identifying Claude as a collaborator\n * and parses the server's awareness state into a list of other collaborators.\n */\n\nimport type { CollaboratorInfo, AwarenessLocalState } from '../yjs/types.js';\nimport type { AwarenessState } from '../wordpress/types.js';\nimport type { WPUser } from '../wordpress/types.js';\n\n/**\n * Build the local awareness state that identifies Claude as a collaborator.\n * This state is sent with each sync request.\n */\nexport function buildAwarenessState(user: WPUser): AwarenessLocalState {\n return {\n collaboratorInfo: {\n id: user.id,\n name: `${user.name} (Claude)`,\n slug: user.slug,\n avatar_urls: user.avatar_urls ?? {},\n browserType: 'Claude Code MCP',\n enteredAt: Date.now(),\n },\n // editorState with selection is required for Gutenberg to recognize us\n // as an active editor and process our CRDT updates in the live session.\n editorState: {\n selection: { type: 'none' },\n },\n };\n}\n\n/**\n * Parse the server's awareness state into a list of collaborators.\n * Excludes our own client ID and null (disconnected) states.\n */\nexport function parseCollaborators(\n awarenessState: AwarenessState,\n ownClientId: number,\n): CollaboratorInfo[] {\n const collaborators: CollaboratorInfo[] = [];\n\n for (const [clientIdStr, state] of Object.entries(awarenessState)) {\n const clientId = Number(clientIdStr);\n if (clientId === ownClientId) {\n continue;\n }\n if (state === null || state === undefined) {\n continue;\n }\n const info = (state as { collaboratorInfo?: CollaboratorInfo })\n .collaboratorInfo;\n if (info) {\n collaborators.push(info);\n }\n }\n\n return collaborators;\n}\n","/**\n * Session manager: orchestrates the full connection lifecycle for\n * collaborative editing of WordPress posts via the Gutenberg sync protocol.\n *\n * Lifecycle: connect → openPost → edit/read → closePost → disconnect\n */\n\nimport * as Y from 'yjs';\nimport { DocumentManager } from '../yjs/document-manager.js';\nimport { WordPressApiClient } from '../wordpress/api-client.js';\nimport { SyncClient } from '../wordpress/sync-client.js';\nimport {\n createSyncStep1,\n processIncomingUpdate,\n createCompactionUpdate,\n createUpdateFromChange,\n} from '../yjs/sync-protocol.js';\nimport {\n computeTextDelta,\n findHtmlSafeChunkEnd,\n} from '../yjs/block-converter.js';\nimport { parseBlocks, parsedBlockToBlock } from '../blocks/parser.js';\nimport { renderPost, renderBlock } from '../blocks/renderer.js';\nimport { buildAwarenessState, parseCollaborators } from './awareness.js';\nimport { DEFAULT_SYNC_CONFIG } from '../wordpress/types.js';\nimport type { Block, CollaboratorInfo, AwarenessLocalState } from '../yjs/types.js';\nimport { isRichTextAttribute, getDefaultAttributes } from '../yjs/types.js';\nimport type {\n WordPressConfig,\n WPUser,\n WPPost,\n} from '../wordpress/types.js';\n\nexport type SessionState = 'disconnected' | 'connected' | 'editing';\n\n/**\n * Origin marker for local edits made through the session manager.\n * Used to distinguish local changes from sync updates when observing Y.Doc events.\n */\nconst LOCAL_ORIGIN = 'local';\n\n/** Streaming chunk size range in characters. Randomized for a natural feel. */\nconst STREAM_CHUNK_SIZE_MIN = 2;\nconst STREAM_CHUNK_SIZE_MAX = 6;\n\n/** Delay between streaming chunks in milliseconds. */\nconst STREAM_CHUNK_DELAY_MS = 200;\n\n/** Minimum text length to trigger streaming (short text is applied atomically). */\nconst STREAM_THRESHOLD = 20;\n\n/** Input shape for blocks with optional recursive inner blocks. */\nexport interface BlockInput {\n name: string;\n content?: string;\n attributes?: Record<string, unknown>;\n innerBlocks?: BlockInput[];\n}\n\n/** A streaming target: a specific attribute in a block that needs progressive insertion. */\ninterface StreamTarget {\n blockIndex: string;\n attrName: string;\n value: string;\n}\n\n/**\n * Recursively prepare a block tree for insertion.\n * Applies default attributes, sets isValid/clientId, and separates\n * streamable rich-text content from atomic structure.\n *\n * @returns The Block (with empty placeholders for streamable content)\n * and a flat list of StreamTargets for progressive insertion.\n */\nfunction prepareBlockTree(\n input: BlockInput,\n indexPrefix: string,\n): { block: Block; streamTargets: StreamTarget[] } {\n const defaults = getDefaultAttributes(input.name);\n const attrs = { ...defaults, ...input.attributes };\n const streamTargets: StreamTarget[] = [];\n\n // Handle 'content' field\n if (input.content !== undefined) {\n if (\n isRichTextAttribute(input.name, 'content') &&\n input.content.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ blockIndex: indexPrefix, attrName: 'content', value: input.content });\n attrs.content = '';\n } else {\n attrs.content = input.content;\n }\n }\n\n // Check other attributes for streaming\n for (const [key, value] of Object.entries(attrs)) {\n if (\n key !== 'content' &&\n isRichTextAttribute(input.name, key) &&\n typeof value === 'string' &&\n value.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ blockIndex: indexPrefix, attrName: key, value });\n attrs[key] = '';\n }\n }\n\n // Recurse into inner blocks\n const innerBlocks: Block[] = [];\n if (input.innerBlocks) {\n for (let i = 0; i < input.innerBlocks.length; i++) {\n const childIndex = `${indexPrefix}.${i}`;\n const prepared = prepareBlockTree(input.innerBlocks[i], childIndex);\n innerBlocks.push(prepared.block);\n streamTargets.push(...prepared.streamTargets);\n }\n }\n\n const block: Block = {\n name: input.name,\n clientId: crypto.randomUUID(),\n attributes: attrs,\n innerBlocks,\n isValid: true,\n };\n\n return { block, streamTargets };\n}\n\nexport class SessionManager {\n private apiClient: WordPressApiClient | null = null;\n private syncClient: SyncClient | null = null;\n private documentManager: DocumentManager;\n private doc: Y.Doc | null = null;\n private user: WPUser | null = null;\n private currentPost: WPPost | null = null;\n private state: SessionState = 'disconnected';\n private awarenessState: AwarenessLocalState | null = null;\n private collaborators: CollaboratorInfo[] = [];\n private updateHandler: ((update: Uint8Array, origin: unknown) => void) | null = null;\n\n /** Max time (ms) to wait for sync to populate the doc before loading from REST API. Set to 0 in tests. */\n syncWaitTimeout = 5000;\n\n constructor() {\n this.documentManager = new DocumentManager();\n }\n\n // --- Connection ---\n\n /**\n * Connect to a WordPress site.\n * Validates credentials and sync endpoint availability.\n */\n async connect(config: WordPressConfig): Promise<WPUser> {\n this.apiClient = new WordPressApiClient(config);\n\n // Validate credentials\n const user = await this.apiClient.validateConnection();\n this.user = user;\n\n // Validate sync endpoint is available\n await this.apiClient.validateSyncEndpoint();\n\n // Build awareness state from user info\n this.awarenessState = buildAwarenessState(user);\n\n this.state = 'connected';\n return user;\n }\n\n /**\n * Disconnect from the WordPress site.\n */\n disconnect(): void {\n if (this.state === 'editing') {\n this.closePost();\n }\n\n this.apiClient = null;\n this.user = null;\n this.awarenessState = null;\n this.collaborators = [];\n this.state = 'disconnected';\n }\n\n // --- Posts ---\n\n /**\n * List posts (delegates to API client).\n */\n async listPosts(options?: {\n status?: string;\n search?: string;\n perPage?: number;\n }): Promise<WPPost[]> {\n this.requireState('connected', 'editing');\n return this.apiClient!.listPosts(options);\n }\n\n /**\n * Open a post for collaborative editing.\n * Creates Y.Doc, loads initial content, starts sync.\n */\n async openPost(postId: number): Promise<void> {\n this.requireState('connected');\n\n // Fetch post from API\n const post = await this.apiClient!.getPost(postId);\n this.currentPost = post;\n\n // Create an EMPTY Y.Doc — don't load content yet.\n // We first sync with the server to receive any existing CRDT state.\n // Loading content independently would create divergent CRDT histories,\n // causing duplicate blocks when two clients sync.\n const doc = this.documentManager.createDoc();\n this.doc = doc;\n\n // Create sync client\n const syncClient = new SyncClient(this.apiClient!, { ...DEFAULT_SYNC_CONFIG });\n this.syncClient = syncClient;\n\n // Start sync with room = postType/${post.type}:${postId}\n const room = `postType/${post.type}:${postId}`;\n const initialUpdates = [createSyncStep1(doc)];\n\n syncClient.start(room, doc.clientID, initialUpdates, {\n onUpdate: (update) => {\n try {\n return processIncomingUpdate(doc, update);\n } catch {\n return null;\n }\n },\n onAwareness: (awarenessState) => {\n this.collaborators = parseCollaborators(awarenessState, doc.clientID);\n },\n onStatusChange: () => {\n // Status is read directly from syncClient.getStatus()\n },\n onCompactionRequested: () => {\n return createCompactionUpdate(doc);\n },\n getAwarenessState: () => {\n return this.awarenessState;\n },\n });\n\n // Wait for the sync handshake to populate the doc with remote content.\n // The handshake takes multiple poll cycles:\n // Poll 1: We send sync_step1 → receive peer's sync_step1\n // Poll 2: We send sync_step2 → receive peer's sync_step2 (their full state)\n // So we wait until the doc has blocks (meaning remote state arrived),\n // or timeout (meaning no peers are editing this post).\n if (this.syncWaitTimeout > 0) {\n await new Promise<void>((resolve) => {\n let resolved = false;\n const done = () => {\n if (!resolved) {\n resolved = true;\n doc.off('update', onDocUpdate);\n resolve();\n }\n };\n\n const timeout = setTimeout(done, this.syncWaitTimeout);\n\n const onDocUpdate = () => {\n const blocks = this.documentManager.getBlocks(doc);\n const title = this.documentManager.getTitle(doc);\n if (blocks.length > 0 || title.length > 0) {\n clearTimeout(timeout);\n done();\n }\n };\n\n doc.on('update', onDocUpdate);\n });\n }\n\n // If the doc is still empty after sync, load content from the REST API.\n // This means we're the first CRDT client for this post.\n const existingBlocks = this.documentManager.getBlocks(doc);\n if (existingBlocks.length === 0) {\n doc.transact(() => {\n // Set title\n if (post.title.raw) {\n this.documentManager.setTitle(doc, post.title.raw);\n }\n\n // Parse content into blocks\n if (post.content.raw) {\n const parsedBlocks = parseBlocks(post.content.raw);\n const blocks = parsedBlocks.map(parsedBlockToBlock);\n this.documentManager.setBlocks(doc, blocks);\n this.documentManager.setContent(doc, post.content.raw);\n }\n\n // Set excerpt\n if (post.excerpt.raw) {\n this.documentManager.setProperty(doc, 'excerpt', post.excerpt.raw);\n }\n\n // Set other post properties\n this.documentManager.setProperty(doc, 'status', post.status);\n this.documentManager.setProperty(doc, 'slug', post.slug);\n this.documentManager.setProperty(doc, 'author', post.author);\n }, LOCAL_ORIGIN);\n }\n\n // Set up Y.Doc observer to queue updates for local changes\n this.updateHandler = (update: Uint8Array, origin: unknown) => {\n // Only queue updates from local edits, not from sync\n if (origin === LOCAL_ORIGIN) {\n const syncUpdate = createUpdateFromChange(update);\n syncClient.queueUpdate(syncUpdate);\n }\n };\n doc.on('update', this.updateHandler);\n\n this.state = 'editing';\n }\n\n /**\n * Create a new post and open it for editing.\n */\n async createPost(data: {\n title?: string;\n content?: string;\n }): Promise<WPPost> {\n this.requireState('connected');\n\n const post = await this.apiClient!.createPost({\n title: data.title,\n content: data.content,\n status: 'draft',\n });\n\n await this.openPost(post.id);\n\n return post;\n }\n\n /**\n * Close the currently open post (stop sync).\n */\n closePost(): void {\n if (this.syncClient) {\n this.syncClient.stop();\n this.syncClient = null;\n }\n\n if (this.doc && this.updateHandler) {\n this.doc.off('update', this.updateHandler);\n this.updateHandler = null;\n }\n\n this.doc = null;\n this.currentPost = null;\n this.collaborators = [];\n this.state = 'connected';\n }\n\n // --- Reading ---\n\n /**\n * Render the current post as Claude-friendly text.\n */\n readPost(): string {\n this.requireState('editing');\n\n const title = this.documentManager.getTitle(this.doc!);\n const blocks = this.documentManager.getBlocks(this.doc!);\n return renderPost(title, blocks);\n }\n\n /**\n * Read a specific block by index (dot notation).\n */\n readBlock(index: string): string {\n this.requireState('editing');\n\n const block = this.documentManager.getBlockByIndex(this.doc!, index);\n if (!block) {\n throw new Error(`Block not found at index ${index}`);\n }\n return renderBlock(block, index);\n }\n\n // --- Editing ---\n\n /**\n * Update a block's content and/or attributes.\n *\n * Rich-text attributes that exceed the streaming threshold are streamed\n * in chunks so the browser sees progressive updates (like fast typing).\n * Non-rich-text and short changes are applied atomically.\n */\n async updateBlock(\n index: string,\n changes: { content?: string; attributes?: Record<string, unknown> },\n ): Promise<void> {\n this.requireState('editing');\n\n // Set cursor position BEFORE the edit — pointing to existing items\n // the browser already has. Gutenberg requires a real cursor position\n // to process remote edits, but if we set it AFTER the edit, the cursor\n // references new items the browser doesn't have yet (causing a crash).\n this.updateCursorPosition(index);\n\n // Identify which changes should be streamed vs applied atomically.\n // Look up the block name to determine rich-text attributes.\n const block = this.documentManager.getBlockByIndex(this.doc!, index);\n if (!block) return;\n\n const streamTargets: Array<{ attrName: string; newValue: string }> = [];\n const atomicChanges: { content?: string; attributes?: Record<string, unknown> } = {};\n\n // Check 'content' field\n if (changes.content !== undefined) {\n if (isRichTextAttribute(block.name, 'content') && changes.content.length >= STREAM_THRESHOLD) {\n streamTargets.push({ attrName: 'content', newValue: changes.content });\n } else {\n atomicChanges.content = changes.content;\n }\n }\n\n // Check explicit attributes\n if (changes.attributes) {\n const atomicAttrs: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(changes.attributes)) {\n if (\n isRichTextAttribute(block.name, key) &&\n typeof value === 'string' &&\n value.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ attrName: key, newValue: value });\n } else {\n atomicAttrs[key] = value;\n }\n }\n if (Object.keys(atomicAttrs).length > 0) {\n atomicChanges.attributes = atomicAttrs;\n }\n }\n\n // Apply atomic changes (non-streaming) in one transaction\n if (atomicChanges.content !== undefined || atomicChanges.attributes) {\n this.doc!.transact(() => {\n this.documentManager.updateBlock(this.doc!, index, atomicChanges);\n }, LOCAL_ORIGIN);\n }\n\n // Stream each rich-text attribute\n for (const target of streamTargets) {\n let ytext = this.documentManager.getBlockAttributeYText(this.doc!, index, target.attrName);\n if (!ytext) {\n // Y.Text doesn't exist yet — create it atomically before streaming\n this.doc!.transact(() => {\n this.documentManager.updateBlock(this.doc!, index, {\n ...(target.attrName === 'content' ? { content: '' } : { attributes: { [target.attrName]: '' } }),\n });\n }, LOCAL_ORIGIN);\n ytext = this.documentManager.getBlockAttributeYText(this.doc!, index, target.attrName);\n }\n if (ytext) {\n await this.streamTextToYText(ytext, target.newValue, index);\n }\n }\n }\n\n /**\n * Insert a new block at position.\n *\n * The block structure (with empty content) is inserted atomically,\n * then rich-text content is streamed in progressively.\n * Supports recursive inner blocks.\n */\n async insertBlock(\n position: number,\n block: BlockInput,\n ): Promise<void> {\n this.requireState('editing');\n\n const blockIndex = String(position);\n const { block: fullBlock, streamTargets } = prepareBlockTree(block, blockIndex);\n\n // Insert block structure atomically\n this.doc!.transact(() => {\n this.documentManager.insertBlock(this.doc!, position, fullBlock);\n }, LOCAL_ORIGIN);\n\n // Stream rich-text content (depth-first: parent first, then children)\n await this.streamTargets(streamTargets);\n }\n\n /**\n * Remove blocks starting at index.\n */\n removeBlocks(startIndex: number, count: number): void {\n this.requireState('editing');\n this.doc!.transact(() => {\n this.documentManager.removeBlocks(this.doc!, startIndex, count);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Move a block from one position to another.\n */\n moveBlock(fromIndex: number, toIndex: number): void {\n this.requireState('editing');\n this.doc!.transact(() => {\n this.documentManager.moveBlock(this.doc!, fromIndex, toIndex);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Replace a range of blocks with new ones.\n *\n * Old blocks are removed and new block structures (with empty content)\n * are inserted atomically. Rich-text content is then streamed progressively.\n */\n async replaceBlocks(\n startIndex: number,\n count: number,\n newBlocks: BlockInput[],\n ): Promise<void> {\n this.requireState('editing');\n\n // Prepare all blocks recursively\n const allStreamTargets: StreamTarget[] = [];\n const fullBlocks: Block[] = newBlocks.map((b, i) => {\n const blockIndex = String(startIndex + i);\n const { block, streamTargets } = prepareBlockTree(b, blockIndex);\n allStreamTargets.push(...streamTargets);\n return block;\n });\n\n // Remove old blocks and insert new structures atomically\n this.doc!.transact(() => {\n this.documentManager.removeBlocks(this.doc!, startIndex, count);\n for (let i = 0; i < fullBlocks.length; i++) {\n this.documentManager.insertBlock(\n this.doc!,\n startIndex + i,\n fullBlocks[i],\n );\n }\n }, LOCAL_ORIGIN);\n\n // Stream content for all blocks (depth-first order)\n await this.streamTargets(allStreamTargets);\n }\n\n /**\n * Insert a block as an inner block of an existing block.\n */\n async insertInnerBlock(\n parentIndex: string,\n position: number,\n block: BlockInput,\n ): Promise<void> {\n this.requireState('editing');\n\n const blockIndex = `${parentIndex}.${position}`;\n const { block: fullBlock, streamTargets } = prepareBlockTree(block, blockIndex);\n\n this.doc!.transact(() => {\n this.documentManager.insertInnerBlock(this.doc!, parentIndex, position, fullBlock);\n }, LOCAL_ORIGIN);\n\n await this.streamTargets(streamTargets);\n }\n\n /**\n * Remove inner blocks from an existing block.\n */\n removeInnerBlocks(parentIndex: string, startIndex: number, count: number): void {\n this.requireState('editing');\n this.doc!.transact(() => {\n this.documentManager.removeInnerBlocks(this.doc!, parentIndex, startIndex, count);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Set the post title.\n *\n * Long titles are streamed progressively; short titles are applied atomically.\n */\n async setTitle(title: string): Promise<void> {\n this.requireState('editing');\n\n if (title.length < STREAM_THRESHOLD) {\n this.doc!.transact(() => {\n this.documentManager.setTitle(this.doc!, title);\n }, LOCAL_ORIGIN);\n return;\n }\n\n // Get the title Y.Text\n const documentMap = this.documentManager.getDocumentMap(this.doc!);\n let ytext = documentMap.get('title');\n if (!(ytext instanceof Y.Text)) {\n // Create Y.Text if it doesn't exist\n this.doc!.transact(() => {\n const newYText = new Y.Text();\n documentMap.set('title', newYText);\n }, LOCAL_ORIGIN);\n ytext = documentMap.get('title');\n }\n if (ytext instanceof Y.Text) {\n await this.streamTextToYText(ytext, title);\n }\n }\n\n /**\n * Trigger a save.\n */\n save(): void {\n this.requireState('editing');\n this.doc!.transact(() => {\n this.documentManager.markSaved(this.doc!);\n }, LOCAL_ORIGIN);\n }\n\n // --- Status ---\n\n getState(): SessionState {\n return this.state;\n }\n\n getSyncStatus(): {\n isPolling: boolean;\n hasCollaborators: boolean;\n queueSize: number;\n } | null {\n if (!this.syncClient) {\n return null;\n }\n const status = this.syncClient.getStatus();\n return {\n isPolling: status.isPolling,\n hasCollaborators: status.hasCollaborators,\n queueSize: status.queueSize,\n };\n }\n\n getCollaborators(): CollaboratorInfo[] {\n return this.collaborators;\n }\n\n getCurrentPost(): WPPost | null {\n return this.currentPost;\n }\n\n getUser(): WPUser | null {\n return this.user;\n }\n\n /**\n * Stream text into a Y.Text in chunks, flushing the sync client between\n * each chunk so the browser sees progressive updates (like fast typing).\n *\n * 1. Compute the delta between the current and target text.\n * 2. Apply retain + delete atomically (old text removed immediately).\n * 3. Split the insert text into HTML-safe chunks (~20 chars each).\n * 4. For each chunk: apply in its own transaction, flush, and delay.\n */\n /**\n * Stream a list of targets (from prepareBlockTree) into their Y.Text instances.\n */\n private async streamTargets(targets: StreamTarget[]): Promise<void> {\n for (const target of targets) {\n let ytext = this.documentManager.getBlockAttributeYText(this.doc!, target.blockIndex, target.attrName);\n if (!ytext) {\n // Y.Text doesn't exist yet — create it atomically before streaming\n this.doc!.transact(() => {\n this.documentManager.updateBlock(this.doc!, target.blockIndex, {\n ...(target.attrName === 'content' ? { content: '' } : { attributes: { [target.attrName]: '' } }),\n });\n }, LOCAL_ORIGIN);\n ytext = this.documentManager.getBlockAttributeYText(this.doc!, target.blockIndex, target.attrName);\n }\n if (ytext) {\n await this.streamTextToYText(ytext, target.value, target.blockIndex);\n }\n }\n }\n\n private async streamTextToYText(ytext: Y.Text, newValue: string, blockIndex?: string): Promise<void> {\n const oldValue = ytext.toString();\n const delta = computeTextDelta(oldValue, newValue);\n if (!delta) return;\n\n // Set cursor to the block being edited\n if (blockIndex !== undefined) {\n this.updateCursorPosition(blockIndex);\n }\n\n // Apply retain + delete atomically (remove old text immediately)\n if (delta.deleteCount > 0) {\n this.doc!.transact(() => {\n const ops: Array<{ retain?: number; delete?: number }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n ops.push({ delete: delta.deleteCount });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n\n if (this.syncClient) {\n this.syncClient.flushQueue();\n }\n }\n\n // If there's nothing to insert, we're done\n if (delta.insertText.length === 0) return;\n\n // For short inserts, apply atomically (no streaming overhead)\n if (delta.insertText.length < STREAM_THRESHOLD) {\n this.doc!.transact(() => {\n const ops: Array<{ retain?: number; insert?: string }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n ops.push({ insert: delta.insertText });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n return;\n }\n\n // Stream the insert text in chunks.\n // Use Yjs relative positions to track the insertion point so that\n // concurrent edits (e.g., user typing earlier in the block) don't\n // throw off our position. The relative position is created right after\n // inserting a chunk (anchored to a CRDT item), then resolved AFTER the\n // flush+delay when remote edits may have shifted absolute positions.\n let offset = 0;\n let insertPos = delta.prefixLen;\n let nextInsertRelPos: Y.RelativePosition | null = null;\n\n while (offset < delta.insertText.length) {\n // Early exit: bail if session is no longer active\n if (!this.doc || !this.syncClient) return;\n\n // If we have a relative position from the previous chunk, resolve it\n // now (after the delay, when remote edits may have been applied).\n if (nextInsertRelPos) {\n const absPos = Y.createAbsolutePositionFromRelativePosition(nextInsertRelPos, this.doc);\n if (absPos) {\n insertPos = absPos.index;\n }\n nextInsertRelPos = null;\n }\n\n const chunkSize = STREAM_CHUNK_SIZE_MIN + Math.floor(Math.random() * (STREAM_CHUNK_SIZE_MAX - STREAM_CHUNK_SIZE_MIN + 1));\n const chunkEnd = findHtmlSafeChunkEnd(delta.insertText, offset, chunkSize);\n const chunk = delta.insertText.slice(offset, chunkEnd);\n\n this.doc.transact(() => {\n const ops: Array<{ retain?: number; insert?: string }> = [];\n if (insertPos > 0) ops.push({ retain: insertPos });\n ops.push({ insert: chunk });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n\n // Anchor a relative position at the end of what we just inserted.\n // This tracks the CRDT item, not the absolute offset, so it survives\n // concurrent edits that shift positions.\n insertPos += chunk.length;\n nextInsertRelPos = Y.createRelativePositionFromTypeIndex(ytext, insertPos);\n\n offset = chunkEnd;\n\n // Update cursor to the end of the inserted text so far\n this.updateCursorOffset(insertPos);\n\n // Flush and delay between chunks (but not after the last one)\n if (offset < delta.insertText.length) {\n this.syncClient.flushQueue();\n await new Promise((resolve) => setTimeout(resolve, STREAM_CHUNK_DELAY_MS));\n }\n }\n }\n\n /**\n * Update the awareness cursor to point to a block's Y.Text type.\n * References the Y.Text type itself (not items within it) so the\n * cursor always resolves — even after updateYText deletes all items.\n */\n private updateCursorPosition(blockIndex: string): void {\n if (!this.doc || !this.user) return;\n\n const ytext = this.documentManager.getBlockContentYText(this.doc, blockIndex);\n if (!ytext) return;\n\n // Get the Y.Text's internal item ID — this references the Y.Text TYPE,\n // not its content items. The type is never deleted, so this always resolves.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const typeItem = (ytext as any)._item;\n if (!typeItem?.id) return;\n\n const relPosJSON = {\n type: { client: typeItem.id.client, clock: typeItem.id.clock },\n tname: null,\n item: null,\n assoc: 0,\n };\n\n // Preserve enteredAt from existing awareness\n const enteredAt = this.awarenessState?.collaboratorInfo.enteredAt ?? Date.now();\n\n this.awarenessState = {\n collaboratorInfo: {\n id: this.user.id,\n name: `${this.user.name} (Claude)`,\n slug: this.user.slug,\n avatar_urls: this.user.avatar_urls ?? {},\n browserType: 'Claude Code MCP',\n enteredAt,\n },\n editorState: {\n selection: {\n type: 'cursor',\n cursorPosition: {\n relativePosition: relPosJSON,\n absoluteOffset: 0,\n },\n },\n },\n };\n }\n\n /**\n * Update just the cursor offset within the current awareness position.\n * Used during streaming to move the cursor forward as text is typed.\n */\n private updateCursorOffset(offset: number): void {\n if (!this.awarenessState?.editorState?.selection) return;\n const selection = this.awarenessState.editorState.selection;\n if (selection.type === 'cursor') {\n selection.cursorPosition.absoluteOffset = offset;\n }\n }\n\n // --- Internal ---\n\n /**\n * Assert that the session is in one of the allowed states.\n */\n private requireState(...allowed: SessionState[]): void {\n if (!allowed.includes(this.state)) {\n throw new Error(\n `Operation requires state ${allowed.join(' or ')}, but current state is '${this.state}'`,\n );\n }\n }\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerConnectTools(server: McpServer, session: SessionManager): void {\n server.tool(\n 'wp_connect',\n 'Connect to a WordPress site for collaborative editing',\n {\n siteUrl: z.string().describe('WordPress site URL (e.g., https://example.com)'),\n username: z.string().describe('WordPress username'),\n appPassword: z.string().describe('WordPress Application Password'),\n },\n async ({ siteUrl, username, appPassword }) => {\n try {\n const user = await session.connect({ siteUrl, username, appPassword });\n return {\n content: [{ type: 'text' as const, text: `Connected to ${siteUrl} as ${user.name} (ID: ${user.id})` }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Connection failed: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_disconnect',\n 'Disconnect from the WordPress site',\n {},\n async () => {\n session.disconnect();\n return {\n content: [{ type: 'text' as const, text: 'Disconnected from WordPress.' }],\n };\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerPostTools(server: McpServer, session: SessionManager): void {\n server.tool(\n 'wp_list_posts',\n 'List WordPress posts with optional filters',\n {\n status: z.string().optional().describe('Filter by post status (e.g., publish, draft, pending)'),\n search: z.string().optional().describe('Search posts by keyword'),\n perPage: z.number().optional().describe('Number of posts to return (default 10)'),\n },\n async ({ status, search, perPage }) => {\n try {\n const posts = await session.listPosts({ status, search, perPage });\n if (posts.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No posts found.' }],\n };\n }\n\n const lines = posts.map(\n (post, i) =>\n `${i + 1}. [${post.id}] ${post.title.raw ?? post.title.rendered} (${post.status})`,\n );\n\n return {\n content: [{\n type: 'text' as const,\n text: `Found ${posts.length} posts:\\n\\n${lines.join('\\n')}`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to list posts: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_open_post',\n 'Open a WordPress post for collaborative editing',\n {\n postId: z.number().describe('The post ID to open'),\n },\n async ({ postId }) => {\n try {\n await session.openPost(postId);\n const content = session.readPost();\n return {\n content: [{\n type: 'text' as const,\n text: `Opened post ${postId} for editing.\\n\\n${content}`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to open post: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_create_post',\n 'Create a new WordPress post and open it for editing',\n {\n title: z.string().optional().describe('Post title'),\n content: z.string().optional().describe('Initial post content (Gutenberg HTML)'),\n },\n async ({ title, content }) => {\n try {\n const post = await session.createPost({ title, content });\n const rendered = session.readPost();\n return {\n content: [{\n type: 'text' as const,\n text: `Created and opened post ${post.id}.\\n\\n${rendered}`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to create post: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerReadTools(server: McpServer, session: SessionManager): void {\n server.tool(\n 'wp_read_post',\n 'Read the current post content as a block listing',\n {},\n async () => {\n try {\n const content = session.readPost();\n return {\n content: [{ type: 'text' as const, text: content }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to read post: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_read_block',\n 'Read a specific block by index (supports dot notation for nested blocks, e.g., \"2.1\")',\n {\n index: z.string().describe('Block index (e.g., \"0\", \"2.1\" for nested blocks)'),\n },\n async ({ index }) => {\n try {\n const content = session.readBlock(index);\n return {\n content: [{ type: 'text' as const, text: content }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to read block: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\n/**\n * Recursive block input schema for nested blocks.\n * Uses z.lazy() for self-referential innerBlocks.\n */\ninterface BlockInput {\n name: string;\n content?: string;\n attributes?: Record<string, unknown>;\n innerBlocks?: BlockInput[];\n}\n\nconst blockInputSchema: z.ZodType<BlockInput> = z.object({\n name: z.string().describe('Block type name (e.g., \"core/paragraph\", \"core/list-item\")'),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z.lazy(() => z.array(blockInputSchema)).optional()\n .describe('Nested child blocks (e.g., list-items inside a list)'),\n});\n\nexport function registerEditTools(server: McpServer, session: SessionManager): void {\n server.tool(\n 'wp_update_block',\n 'Update a block\\'s content and/or attributes',\n {\n index: z.string().describe('Block index (e.g., \"0\", \"2.1\" for nested blocks)'),\n content: z.string().optional().describe('New text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Attributes to update (key-value pairs)'),\n },\n async ({ index, content, attributes }) => {\n try {\n await session.updateBlock(index, { content, attributes });\n const updated = session.readBlock(index);\n return {\n content: [{ type: 'text' as const, text: `Updated block ${index}.\\n\\n${updated}` }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to update block: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_insert_block',\n 'Insert a new block at a position in the post. Supports nested blocks via innerBlocks.',\n {\n position: z.number().describe('Position to insert the block (0-based index)'),\n name: z.string().describe('Block type name (e.g., \"core/paragraph\", \"core/heading\", \"core/list\")'),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z.array(blockInputSchema).optional()\n .describe('Nested child blocks (e.g., list-items inside a list)'),\n },\n async ({ position, name, content, attributes, innerBlocks }) => {\n try {\n await session.insertBlock(position, { name, content, attributes, innerBlocks });\n return {\n content: [{ type: 'text' as const, text: `Inserted ${name} block at position ${position}.` }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to insert block: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_insert_inner_block',\n 'Insert a block as a child of an existing block (e.g., add a list-item to a list)',\n {\n parentIndex: z.string().describe('Dot-notation index of the parent block (e.g., \"0\", \"2.1\")'),\n position: z.number().describe('Position within the parent\\'s inner blocks (0-based)'),\n name: z.string().describe('Block type name (e.g., \"core/list-item\")'),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z.array(blockInputSchema).optional()\n .describe('Nested child blocks'),\n },\n async ({ parentIndex, position, name, content, attributes, innerBlocks }) => {\n try {\n await session.insertInnerBlock(parentIndex, position, { name, content, attributes, innerBlocks });\n return {\n content: [{ type: 'text' as const, text: `Inserted ${name} as inner block at ${parentIndex}.${position}.` }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to insert inner block: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_remove_blocks',\n 'Remove one or more blocks from the post',\n {\n startIndex: z.number().describe('Index of the first block to remove'),\n count: z.number().optional().describe('Number of blocks to remove (default 1)'),\n },\n async ({ startIndex, count }) => {\n try {\n const removeCount = count ?? 1;\n session.removeBlocks(startIndex, removeCount);\n return {\n content: [{\n type: 'text' as const,\n text: `Removed ${removeCount} block${removeCount !== 1 ? 's' : ''} starting at index ${startIndex}.`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to remove blocks: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_remove_inner_blocks',\n 'Remove inner blocks from a parent block',\n {\n parentIndex: z.string().describe('Dot-notation index of the parent block (e.g., \"0\")'),\n startIndex: z.number().describe('Index of the first inner block to remove'),\n count: z.number().optional().describe('Number of inner blocks to remove (default 1)'),\n },\n async ({ parentIndex, startIndex, count }) => {\n try {\n const removeCount = count ?? 1;\n session.removeInnerBlocks(parentIndex, startIndex, removeCount);\n return {\n content: [{\n type: 'text' as const,\n text: `Removed ${removeCount} inner block${removeCount !== 1 ? 's' : ''} from block ${parentIndex}.`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to remove inner blocks: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_move_block',\n 'Move a block from one position to another',\n {\n fromIndex: z.number().describe('Current position of the block'),\n toIndex: z.number().describe('Target position for the block'),\n },\n async ({ fromIndex, toIndex }) => {\n try {\n session.moveBlock(fromIndex, toIndex);\n return {\n content: [{\n type: 'text' as const,\n text: `Moved block from position ${fromIndex} to ${toIndex}.`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to move block: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_replace_blocks',\n 'Replace a range of blocks with new blocks. Supports nested blocks via innerBlocks.',\n {\n startIndex: z.number().describe('Index of the first block to replace'),\n count: z.number().describe('Number of blocks to replace'),\n blocks: z.array(blockInputSchema).describe('New blocks to insert in place of the removed ones'),\n },\n async ({ startIndex, count, blocks }) => {\n try {\n await session.replaceBlocks(startIndex, count, blocks);\n return {\n content: [{\n type: 'text' as const,\n text: `Replaced ${count} block${count !== 1 ? 's' : ''} at index ${startIndex} with ${blocks.length} new block${blocks.length !== 1 ? 's' : ''}.`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to replace blocks: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_set_title',\n 'Set the post title',\n {\n title: z.string().describe('New post title'),\n },\n async ({ title }) => {\n try {\n await session.setTitle(title);\n return {\n content: [{ type: 'text' as const, text: `Title set to \"${title}\".` }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to set title: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerStatusTools(server: McpServer, session: SessionManager): void {\n server.tool(\n 'wp_status',\n 'Show current connection state, sync status, and post info',\n {},\n async () => {\n const state = session.getState();\n const lines: string[] = [];\n\n if (state === 'disconnected') {\n lines.push('Connection: disconnected');\n lines.push('');\n lines.push('Use wp_connect to connect to a WordPress site.');\n } else {\n const user = session.getUser();\n lines.push('Connection: connected');\n lines.push(`User: ${user?.name ?? 'unknown'} (ID: ${user?.id ?? '?'})`);\n\n const post = session.getCurrentPost();\n if (state === 'editing' && post) {\n const syncStatus = session.getSyncStatus();\n const collaboratorCount = session.getCollaborators().length;\n\n lines.push(`Sync: ${syncStatus?.isPolling ? 'polling' : 'stopped'} (${collaboratorCount + 1} collaborator${collaboratorCount + 1 !== 1 ? 's' : ''})`);\n lines.push(`Post: \"${post.title.raw ?? post.title.rendered}\" (ID: ${post.id}, status: ${post.status})`);\n lines.push(`Queue: ${syncStatus?.queueSize ?? 0} pending updates`);\n } else {\n lines.push('Post: none open');\n lines.push('');\n lines.push('Use wp_open_post or wp_create_post to start editing.');\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n server.tool(\n 'wp_collaborators',\n 'List active collaborators on the current post',\n {},\n async () => {\n try {\n const state = session.getState();\n if (state !== 'editing') {\n return {\n content: [{ type: 'text' as const, text: 'No post is currently open for editing.' }],\n isError: true,\n };\n }\n\n const collaborators = session.getCollaborators();\n const user = session.getUser();\n\n const lines: string[] = ['Active collaborators:'];\n\n // Add ourselves first\n if (user) {\n lines.push(`- ${user.name} (AI, Claude Code MCP)`);\n }\n\n // Add remote collaborators\n for (const collab of collaborators) {\n lines.push(`- ${collab.name} (Human, ${collab.browserType})`);\n }\n\n if (collaborators.length === 0 && !user) {\n lines.push('- No collaborators detected');\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to get collaborators: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n\n server.tool(\n 'wp_save',\n 'Save the current post',\n {},\n async () => {\n try {\n session.save();\n const post = session.getCurrentPost();\n return {\n content: [{\n type: 'text' as const,\n text: `Post \"${post?.title.raw ?? post?.title.rendered ?? 'Untitled'}\" saved.`,\n }],\n };\n } catch (error) {\n return {\n content: [{ type: 'text' as const, text: `Failed to save: ${error instanceof Error ? error.message : String(error)}` }],\n isError: true,\n };\n }\n },\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { SessionManager } from './session/session-manager.js';\nimport { registerConnectTools } from './tools/connect.js';\nimport { registerPostTools } from './tools/posts.js';\nimport { registerReadTools } from './tools/read.js';\nimport { registerEditTools } from './tools/edit.js';\nimport { registerStatusTools } from './tools/status.js';\n\ndeclare const __PKG_VERSION__: string;\n\nexport const VERSION = typeof __PKG_VERSION__ !== 'undefined' ? __PKG_VERSION__ : '0.0.0-dev';\n\nexport async function startServer(): Promise<void> {\n const server = new McpServer({\n name: 'claudaborative-editing',\n version: VERSION,\n });\n\n const session = new SessionManager();\n\n // Auto-connect from env vars if available\n const siteUrl = process.env.WP_SITE_URL;\n const username = process.env.WP_USERNAME;\n const appPassword = process.env.WP_APP_PASSWORD;\n\n if (siteUrl && username && appPassword) {\n try {\n await session.connect({ siteUrl, username, appPassword });\n } catch (e) {\n // Don't fail startup — user can connect via wp_connect tool\n console.error('Auto-connect failed:', e);\n }\n }\n\n // Register all tools\n registerConnectTools(server, session);\n registerPostTools(server, session);\n registerReadTools(server, session);\n registerEditTools(server, session);\n registerStatusTools(server, session);\n\n // Start stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","/**\n * Interactive setup wizard for claudaborative-editing.\n *\n * Prompts for WordPress credentials, validates them, and outputs\n * the `claude mcp add` command the user can copy-paste.\n */\n\nimport { createInterface } from 'readline';\nimport { WordPressApiClient, WordPressApiError } from '../wordpress/api-client.js';\n\nexport interface SetupDeps {\n prompt: (question: string) => Promise<string>;\n log: (message: string) => void;\n error: (message: string) => void;\n exit: (code: number) => never;\n cleanup: () => void;\n}\n\nfunction defaultDeps(): SetupDeps {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n return {\n prompt: (question: string) =>\n new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n }),\n log: (msg) => console.log(msg),\n error: (msg) => console.error(`Error: ${msg}`),\n exit: (code) => {\n rl.close();\n return process.exit(code);\n },\n cleanup: () => rl.close(),\n };\n}\n\nexport async function runSetup(deps: SetupDeps = defaultDeps()): Promise<void> {\n const { prompt, log, error, exit, cleanup } = deps;\n\n log('');\n log('claudaborative-editing setup');\n log('============================');\n log('');\n log('This wizard will validate your WordPress credentials and give you');\n log('the command to register this MCP server with Claude Code.');\n log('');\n log('Prerequisites:');\n log(' - WordPress 7.0+ with collaborative editing enabled');\n log(' (Settings → Writing in your WordPress admin)');\n log(' - An Application Password for your WordPress user');\n log(' (Users → Your Profile → Application Passwords)');\n log('');\n\n // 1. Collect credentials\n const siteUrl = await prompt('WordPress site URL: ');\n if (!siteUrl) {\n error('Site URL is required.');\n exit(1);\n }\n\n const username = await prompt('WordPress username: ');\n if (!username) {\n error('Username is required.');\n exit(1);\n }\n\n const appPassword = await prompt('Application Password: ');\n if (!appPassword) {\n error('Application Password is required.');\n exit(1);\n }\n\n log('');\n log('Validating credentials...');\n\n // 2. Validate auth\n const client = new WordPressApiClient({\n siteUrl,\n username,\n appPassword,\n });\n\n let displayName: string;\n try {\n const user = await client.validateConnection();\n displayName = user.name ?? username;\n log(` ✓ Authenticated as \"${displayName}\"`);\n } catch (err) {\n if (err instanceof WordPressApiError) {\n error(err.message);\n } else {\n error(`Could not connect to ${siteUrl}. Check the URL and try again.`);\n }\n exit(1);\n }\n\n // 3. Validate sync endpoint\n try {\n await client.validateSyncEndpoint();\n log(' ✓ Collaborative editing endpoint available');\n } catch (err) {\n if (err instanceof WordPressApiError && err.status === 404) {\n log('');\n error(\n 'Collaborative editing is not enabled.\\n' +\n ' Go to Settings → Writing in your WordPress admin and enable it.\\n' +\n ' (Requires WordPress 7.0 or later.)',\n );\n exit(1);\n }\n if (err instanceof WordPressApiError) {\n error(err.message);\n } else {\n error('Could not validate the sync endpoint.');\n }\n exit(1);\n }\n\n log('');\n log('Setup complete! Run this command to register the MCP server:');\n log('');\n\n // Build the env flags\n const envFlags = [\n `-e WP_SITE_URL=${shellQuote(siteUrl)}`,\n `-e WP_USERNAME=${shellQuote(username)}`,\n `-e WP_APP_PASSWORD=${shellQuote(appPassword)}`,\n ].join(' ');\n\n log(` claude mcp add claudaborative-editing ${envFlags} -- npx claudaborative-editing`);\n log('');\n\n cleanup();\n}\n\n/**\n * Quote a value for safe shell use in the output command.\n * Wraps in double quotes if it contains spaces or special characters.\n */\nexport function shellQuote(value: string): string {\n if (/^[a-zA-Z0-9_./:@-]+$/.test(value)) {\n return value;\n }\n // Escape backslashes, double quotes, dollar signs, backticks\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\$/g, '\\\\$')\n .replace(/`/g, '\\\\`');\n return `\"${escaped}\"`;\n}\n","import { VERSION } from './server.js';\n\nconst args = process.argv.slice(2);\n\nif (args.includes('--version') || args.includes('-v')) {\n console.log(VERSION);\n process.exit(0);\n}\n\nif (args.includes('--help') || args.includes('-h')) {\n console.log(`claudaborative-editing v${VERSION}\n\nMCP server for collaborative WordPress post editing via Yjs CRDT.\n\nUsage:\n claudaborative-editing Start the MCP server (stdio transport)\n claudaborative-editing setup Interactive setup wizard\n claudaborative-editing --version Print version\n claudaborative-editing --help Show this help\n\nEnvironment variables:\n WP_SITE_URL WordPress site URL\n WP_USERNAME WordPress username\n WP_APP_PASSWORD WordPress Application Password\n\nMore info: https://github.com/pento/claudaborative-editing`);\n process.exit(0);\n}\n\nif (args[0] === 'setup') {\n const { runSetup } = await import('./cli/setup.js');\n await runSetup();\n} else {\n const { startServer } = await import('./server.js');\n startServer().catch((error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":["Y","init_types","Y","init_types","Y","init_types","z","z","z","runSetup","startServer"]}
|
|
1
|
+
{"version":3,"sources":["../src/yjs/types.ts","../src/yjs/block-converter.ts","../src/yjs/block-type-registry.ts","../src/yjs/document-manager.ts","../src/wordpress/api-client.ts","../src/wordpress/sync-client.ts","../src/wordpress/types.ts","../src/yjs/sync-protocol.ts","../src/blocks/parser.ts","../src/blocks/renderer.ts","../src/session/awareness.ts","../src/wordpress/mime-types.ts","../src/session/session-manager.ts","../src/tools/connect.ts","../src/tools/posts.ts","../src/tools/read.ts","../src/tools/edit.ts","../src/tools/status.ts","../src/tools/block-types.ts","../src/tools/media.ts","../src/tools/notes.ts","../src/tools/metadata.ts","../src/prompts/editing.ts","../src/prompts/review.ts","../src/prompts/authoring.ts","../src/server.ts","../src/cli/auth-server.ts","../src/cli/clients.ts","../src/cli/config-writer.ts","../src/cli/checkbox-prompt.ts","../src/cli/setup.ts","../src/index.ts"],"sourcesContent":["/**\n * Yjs document types matching the Gutenberg CRDT structure.\n *\n * Verified from @wordpress/sync and @wordpress/core-data source code.\n * The Y.Doc has two root Y.Maps: 'document' and 'state'.\n */\nimport * as Y from 'yjs';\n\n// --- Root-level keys ---\n\nexport const CRDT_RECORD_MAP_KEY = 'document';\nexport const CRDT_STATE_MAP_KEY = 'state';\nexport const CRDT_STATE_MAP_VERSION_KEY = 'version';\nexport const CRDT_STATE_MAP_SAVED_AT_KEY = 'savedAt';\nexport const CRDT_STATE_MAP_SAVED_BY_KEY = 'savedBy';\nexport const CRDT_DOC_VERSION = 1;\n\n// --- Block types ---\n\n/** Block attributes map: rich-text attributes are Y.Text, others are plain values. */\nexport type YBlockAttributes = Y.Map<unknown>;\n\n/** A plain-object block for reading/writing (not Yjs types). */\nexport interface Block {\n name: string;\n clientId: string;\n attributes: Record<string, unknown>;\n innerBlocks: Block[];\n isValid?: boolean;\n originalContent?: string;\n}\n\n// --- Collaborator awareness ---\n\nexport interface CollaboratorInfo {\n id: number;\n name: string;\n slug: string;\n avatar_urls: Record<string, string>;\n browserType: string;\n enteredAt: number;\n}\n\nexport interface AwarenessCursorPosition {\n relativePosition: {\n type: { client: number; clock: number };\n tname: null;\n item: null;\n assoc: number;\n };\n absoluteOffset: number;\n}\n\nexport interface AwarenessEditorState {\n selection: { type: 'none' } | { type: 'cursor'; cursorPosition: AwarenessCursorPosition };\n}\n\nexport interface AwarenessLocalState {\n collaboratorInfo: CollaboratorInfo;\n editorState?: AwarenessEditorState;\n}\n","/**\n * Converts between plain Block objects and Yjs Y.Map types.\n *\n * Handles the mapping of rich-text attributes to Y.Text instances\n * based on the block type's known schema.\n */\nimport * as Y from 'yjs';\nimport type { Block } from './types.js';\nimport type { BlockTypeRegistry } from './block-type-registry.js';\n\n/**\n * Convert a plain Block object to a Y.Map suitable for insertion into the Y.Doc.\n *\n * Rich-text attributes (as determined by the block type) are stored as Y.Text.\n * All other attributes are stored as plain values.\n */\nexport function blockToYMap(block: Block, registry: BlockTypeRegistry): Y.Map<unknown> {\n const ymap = new Y.Map<unknown>();\n\n ymap.set('name', block.name);\n ymap.set('clientId', block.clientId);\n\n if (block.isValid !== undefined) {\n ymap.set('isValid', block.isValid);\n }\n if (block.originalContent !== undefined) {\n ymap.set('originalContent', block.originalContent);\n }\n\n // Attributes: rich-text ones become Y.Text, others stay as plain values\n const attrMap = new Y.Map<unknown>();\n for (const [key, value] of Object.entries(block.attributes)) {\n if (registry.isRichTextAttribute(block.name, key) && typeof value === 'string') {\n const ytext = new Y.Text();\n ytext.insert(0, value);\n attrMap.set(key, ytext);\n } else {\n attrMap.set(key, value);\n }\n }\n ymap.set('attributes', attrMap);\n\n // Inner blocks: recurse\n const innerBlocksArray = new Y.Array<Y.Map<unknown>>();\n if (block.innerBlocks.length > 0) {\n const innerMaps = block.innerBlocks.map((inner) => blockToYMap(inner, registry));\n innerBlocksArray.push(innerMaps);\n }\n ymap.set('innerBlocks', innerBlocksArray);\n\n return ymap;\n}\n\n/**\n * Convert a Y.Map block from the Y.Doc to a plain Block object.\n *\n * Y.Text attributes are converted to their string representation.\n */\nexport function yMapToBlock(ymap: Y.Map<unknown>): Block {\n const name = ymap.get('name') as string;\n const clientId = ymap.get('clientId') as string;\n\n // Read attributes, converting Y.Text to strings\n const attrMap = ymap.get('attributes') as Y.Map<unknown> | undefined;\n const attributes: Record<string, unknown> = {};\n if (attrMap) {\n for (const [key, value] of attrMap.entries()) {\n if (value instanceof Y.Text) {\n attributes[key] = value.toJSON();\n } else {\n attributes[key] = value;\n }\n }\n }\n\n // Read inner blocks recursively\n const innerBlocksArray = ymap.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n const innerBlocks: Block[] = [];\n if (innerBlocksArray) {\n for (let i = 0; i < innerBlocksArray.length; i++) {\n innerBlocks.push(yMapToBlock(innerBlocksArray.get(i)));\n }\n }\n\n const block: Block = {\n name,\n clientId,\n attributes,\n innerBlocks,\n };\n\n const isValid = ymap.get('isValid');\n if (isValid !== undefined) {\n block.isValid = isValid as boolean;\n }\n\n const originalContent = ymap.get('originalContent');\n if (originalContent !== undefined) {\n block.originalContent = originalContent as string;\n }\n\n return block;\n}\n\n/**\n * Result of computing the delta between two strings.\n */\nexport interface TextDelta {\n prefixLen: number;\n deleteCount: number;\n insertText: string;\n}\n\n/**\n * Compute the minimal delta between two strings using common-prefix/common-suffix diff.\n * Returns null if the strings are identical.\n */\nexport function computeTextDelta(oldValue: string, newValue: string): TextDelta | null {\n if (oldValue === newValue) return null;\n\n // Find common prefix\n let prefixLen = 0;\n while (\n prefixLen < oldValue.length &&\n prefixLen < newValue.length &&\n oldValue[prefixLen] === newValue[prefixLen]\n ) {\n prefixLen++;\n }\n\n // Find common suffix (don't overlap with prefix)\n let suffixLen = 0;\n while (\n suffixLen < oldValue.length - prefixLen &&\n suffixLen < newValue.length - prefixLen &&\n oldValue[oldValue.length - 1 - suffixLen] === newValue[newValue.length - 1 - suffixLen]\n ) {\n suffixLen++;\n }\n\n const deleteCount = oldValue.length - prefixLen - suffixLen;\n const insertText = newValue.slice(prefixLen, newValue.length - suffixLen);\n\n return { prefixLen, deleteCount, insertText };\n}\n\n/**\n * Update a Y.Text using delta-based editing via `Y.Text.applyDelta()`.\n *\n * Uses a simple common-prefix/common-suffix diff to compute the minimal\n * retain/delete/insert operations. Delta operations are POSITION-BASED,\n * not item-ID-based, so they operate on whatever CRDT items exist at\n * those positions — whether created by the browser or by us.\n *\n * This is the correct approach for live collaborative editing where\n * Gutenberg's `applyChangesToCRDTDoc` creates local items alongside\n * remote items in Y.Text.\n */\nexport function deltaUpdateYText(ytext: Y.Text, newValue: string): void {\n const oldValue = ytext.toJSON();\n const delta = computeTextDelta(oldValue, newValue);\n if (!delta) return;\n\n // Build delta ops\n const ops: Array<{ retain?: number; delete?: number; insert?: string }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n if (delta.deleteCount > 0) ops.push({ delete: delta.deleteCount });\n if (delta.insertText.length > 0) ops.push({ insert: delta.insertText });\n\n if (ops.length > 0) {\n ytext.applyDelta(ops);\n }\n}\n\n/**\n * Find the end position for an HTML-safe chunk of text.\n *\n * Given text and a starting offset, returns the end position for the next chunk,\n * ensuring it doesn't split inside an HTML tag. If the preferred end position\n * is inside a tag (between `<` and `>`), extends the chunk past the closing `>`.\n *\n * @param text The full text to chunk\n * @param offset The starting offset within the text\n * @param preferredSize The preferred chunk size in characters\n * @returns The end position (exclusive) for the chunk\n */\nexport function findHtmlSafeChunkEnd(text: string, offset: number, preferredSize: number): number {\n const end = Math.min(offset + preferredSize, text.length);\n if (end >= text.length) return text.length;\n\n // Check if we're inside an HTML tag at the proposed end position.\n // Scan backward from end to find the most recent '<' or '>' before the end.\n let inTag = false;\n for (let i = end - 1; i >= offset; i--) {\n if (text[i] === '>') {\n // We found a closing '>' before reaching any '<', so we're NOT inside a tag\n break;\n }\n if (text[i] === '<') {\n // We found an opening '<' without a closing '>' between it and end,\n // so the proposed end is inside a tag\n inTag = true;\n break;\n }\n }\n\n if (!inTag) return end;\n\n // Extend past the closing '>'\n const closingBracket = text.indexOf('>', end);\n if (closingBracket === -1) {\n // No closing bracket found — include the rest of the text\n return text.length;\n }\n return closingBracket + 1;\n}\n","/**\n * Dynamic block type registry built from the WordPress REST API.\n *\n * Replaces the hardcoded RICH_TEXT_ATTRIBUTES / DEFAULT_BLOCK_ATTRIBUTES / SUPPORTED_BLOCK_TYPES\n * with a registry populated from GET /wp/v2/block-types. This allows the MCP server to\n * support ALL block types registered on the WordPress site — core, third-party, and custom.\n */\nimport type { WPBlockType, WPBlockTypeAttribute } from '../wordpress/types.js';\n\n/** Stored metadata for a single block type. */\ninterface BlockTypeEntry {\n name: string;\n title: string;\n /** All known attribute names and their schema definitions. */\n attributeSchemas: Map<string, WPBlockTypeAttribute>;\n richTextAttributes: Set<string>;\n defaults: Record<string, unknown>;\n /** Block types this block can be nested inside. Null = any parent. */\n parent: string[] | null;\n /** Ancestor blocks (looser than parent). Null = any ancestor. */\n ancestor: string[] | null;\n /** Block types allowed as direct children. Null = any. */\n allowedBlocks: string[] | null;\n /** Whether this block declares InnerBlocks support via supports.allowedBlocks === true. */\n supportsInnerBlocks: boolean;\n}\n\n/**\n * Fallback rich-text attributes used when the API is unavailable.\n * Matches the previously hardcoded RICH_TEXT_ATTRIBUTES.\n */\nconst FALLBACK_RICH_TEXT_ATTRIBUTES: Record<string, Set<string>> = {\n 'core/paragraph': new Set(['content']),\n 'core/heading': new Set(['content']),\n 'core/list-item': new Set(['content']),\n 'core/quote': new Set(['value', 'citation']),\n 'core/pullquote': new Set(['value', 'citation']),\n 'core/verse': new Set(['content']),\n 'core/preformatted': new Set(['content']),\n 'core/freeform': new Set(['content']),\n 'core/button': new Set(['text']),\n 'core/table': new Set([]),\n 'core/footnotes': new Set(['content']),\n};\n\n/**\n * Fallback default attributes used when the API is unavailable.\n * Matches the previously hardcoded DEFAULT_BLOCK_ATTRIBUTES.\n */\nconst FALLBACK_DEFAULT_ATTRIBUTES: Record<string, Record<string, unknown>> = {\n 'core/paragraph': { dropCap: false },\n 'core/heading': { level: 2 },\n 'core/list': { ordered: false },\n};\n\n/** Information about a block type for display in the wp_block_types tool. */\nexport interface BlockTypeInfo {\n name: string;\n title: string;\n attributes: Array<{\n name: string;\n type: string;\n richText: boolean;\n default?: unknown;\n }>;\n parent: string[] | null;\n ancestor: string[] | null;\n allowedBlocks: string[] | null;\n /** Whether this block uses InnerBlocks (supports.allowedBlocks === true from API). */\n supportsInnerBlocks: boolean;\n}\n\nexport class BlockTypeRegistry {\n /** Maps block name → full block type entry. */\n private entries: Map<string, BlockTypeEntry>;\n /** Whether this registry was built from the API or is a fallback. */\n private isFallback: boolean;\n\n private constructor(entries: Map<string, BlockTypeEntry>, isFallback: boolean) {\n this.entries = entries;\n this.isFallback = isFallback;\n }\n\n /**\n * Build a registry from the WordPress REST API response.\n * Detects rich-text attributes, extracts defaults, and stores nesting constraints.\n */\n static fromApiResponse(blockTypes: WPBlockType[]): BlockTypeRegistry {\n const entries = new Map<string, BlockTypeEntry>();\n\n for (const blockType of blockTypes) {\n const attributeSchemas = new Map<string, WPBlockTypeAttribute>();\n const richTextSet = new Set<string>();\n const defaults: Record<string, unknown> = {};\n\n if (blockType.attributes) {\n for (const [attrName, attrDef] of Object.entries(blockType.attributes)) {\n attributeSchemas.set(attrName, attrDef);\n\n // Rich-text detection: type === \"rich-text\" OR source === \"rich-text\" OR source === \"html\"\n if (\n attrDef.type === 'rich-text' ||\n attrDef.source === 'rich-text' ||\n attrDef.source === 'html'\n ) {\n richTextSet.add(attrName);\n }\n\n // Extract default values\n if ('default' in attrDef) {\n defaults[attrName] = attrDef.default;\n }\n }\n }\n\n // Normalise parent/ancestor/allowedBlocks: empty arrays and nulls both mean \"no constraint\"\n const parent = blockType.parent?.length ? blockType.parent : null;\n const ancestor = blockType.ancestor?.length ? blockType.ancestor : null;\n const allowedBlocks = blockType.allowed_blocks?.length ? blockType.allowed_blocks : null;\n\n const supportsInnerBlocks = blockType.supports?.allowedBlocks === true;\n\n entries.set(blockType.name, {\n name: blockType.name,\n title: blockType.title ?? blockType.name,\n attributeSchemas,\n richTextAttributes: richTextSet,\n defaults,\n parent,\n ancestor,\n allowedBlocks,\n supportsInnerBlocks,\n });\n }\n\n return new BlockTypeRegistry(entries, false);\n }\n\n /**\n * Create a fallback registry using the hardcoded block type maps.\n * Used when the API call fails (graceful degradation).\n */\n static createFallback(): BlockTypeRegistry {\n const entries = new Map<string, BlockTypeEntry>();\n\n // Collect all known block names from both maps\n const allNames = new Set([\n ...Object.keys(FALLBACK_RICH_TEXT_ATTRIBUTES),\n ...Object.keys(FALLBACK_DEFAULT_ATTRIBUTES),\n ]);\n\n for (const name of allNames) {\n entries.set(name, {\n name,\n title: name,\n attributeSchemas: new Map(),\n richTextAttributes: FALLBACK_RICH_TEXT_ATTRIBUTES[name] ?? new Set(),\n defaults: FALLBACK_DEFAULT_ATTRIBUTES[name] ?? {},\n parent: null,\n ancestor: null,\n allowedBlocks: null,\n supportsInnerBlocks: false,\n });\n }\n\n return new BlockTypeRegistry(entries, true);\n }\n\n /**\n * Check if a block attribute is rich-text typed.\n */\n isRichTextAttribute(blockName: string, attrName: string): boolean {\n return this.entries.get(blockName)?.richTextAttributes.has(attrName) ?? false;\n }\n\n /**\n * Get the names of all rich-text attributes for a block type.\n * Returns an empty array if the block type is unknown.\n */\n getRichTextAttributes(blockName: string): string[] {\n const entry = this.entries.get(blockName);\n return entry ? Array.from(entry.richTextAttributes) : [];\n }\n\n /**\n * Get default attributes for a block type.\n * Returns an empty object if no defaults are defined.\n */\n getDefaultAttributes(blockName: string): Record<string, unknown> {\n return this.entries.get(blockName)?.defaults ?? {};\n }\n\n /**\n * Check if a block type is known to the registry.\n */\n isKnownBlockType(blockName: string): boolean {\n return this.entries.has(blockName);\n }\n\n /**\n * Whether this registry was built from the fallback hardcoded data.\n */\n isUsingFallback(): boolean {\n return this.isFallback;\n }\n\n /**\n * Get a sorted list of known block type names.\n */\n getKnownBlockTypeNames(): string[] {\n return [...this.entries.keys()].sort();\n }\n\n /**\n * Check if a block type has a specific attribute in its schema.\n * Only meaningful for API-sourced registries (fallback has no attribute schemas).\n */\n hasAttribute(blockName: string, attrName: string): boolean {\n const entry = this.entries.get(blockName);\n if (!entry) return false;\n return entry.attributeSchemas.has(attrName);\n }\n\n /**\n * Get all known attribute names for a block type.\n * Returns null if the block type is unknown or if using the fallback registry\n * (which has no attribute schemas). For API-sourced registries, returns an\n * empty Set for blocks with zero attributes so validation remains strict.\n */\n getAttributeNames(blockName: string): Set<string> | null {\n const entry = this.entries.get(blockName);\n if (!entry) return null;\n // Fallback registry has no attribute schemas — return null to skip validation\n if (this.isFallback && entry.attributeSchemas.size === 0) return null;\n return new Set(entry.attributeSchemas.keys());\n }\n\n /**\n * Get the parent constraint for a block type.\n * Returns null if the block can be placed anywhere.\n */\n getParent(blockName: string): string[] | null {\n return this.entries.get(blockName)?.parent ?? null;\n }\n\n /**\n * Get the ancestor constraint for a block type.\n * Returns null if the block has no ancestor constraint.\n */\n getAncestor(blockName: string): string[] | null {\n return this.entries.get(blockName)?.ancestor ?? null;\n }\n\n /**\n * Get the allowed inner block types for a block type.\n * Returns null if any block type is allowed as a child.\n */\n getAllowedBlocks(blockName: string): string[] | null {\n return this.entries.get(blockName)?.allowedBlocks ?? null;\n }\n\n /**\n * Check if a block type supports InnerBlocks (via supports.allowedBlocks in the API).\n * Returns false for unknown block types and for the fallback registry.\n */\n supportsInnerBlocks(blockName: string): boolean {\n return this.entries.get(blockName)?.supportsInnerBlocks ?? false;\n }\n\n /**\n * Get detailed info for a single block type (for the wp_block_types tool).\n * Returns null if the block type is unknown.\n */\n getBlockTypeInfo(blockName: string): BlockTypeInfo | null {\n const entry = this.entries.get(blockName);\n if (!entry) return null;\n\n const attributes: BlockTypeInfo['attributes'] = [];\n for (const [attrName, schema] of entry.attributeSchemas) {\n const attr: BlockTypeInfo['attributes'][0] = {\n name: attrName,\n type: schema.type,\n richText: entry.richTextAttributes.has(attrName),\n };\n if ('default' in schema) {\n attr.default = schema.default;\n }\n attributes.push(attr);\n }\n\n return {\n name: entry.name,\n title: entry.title,\n attributes,\n parent: entry.parent,\n ancestor: entry.ancestor,\n allowedBlocks: entry.allowedBlocks,\n supportsInnerBlocks: entry.supportsInnerBlocks,\n };\n }\n\n /**\n * Search block types by name substring.\n * Returns basic info (name + title) for matching blocks.\n */\n searchBlockTypes(query: string): Array<{ name: string; title: string }> {\n const lowerQuery = query.toLowerCase();\n const results: Array<{ name: string; title: string }> = [];\n for (const entry of this.entries.values()) {\n if (\n entry.name.toLowerCase().includes(lowerQuery) ||\n entry.title.toLowerCase().includes(lowerQuery)\n ) {\n results.push({ name: entry.name, title: entry.title });\n }\n }\n return results.sort((a, b) => a.name.localeCompare(b.name));\n }\n}\n","/**\n * Manages Y.Doc lifecycle for WordPress post collaborative editing.\n *\n * Each Y.Doc mirrors the structure Gutenberg expects:\n * - Root map 'document': holds post fields (title, content, blocks, etc.)\n * - Root map 'state': holds sync metadata (version, savedAt, savedBy)\n */\nimport * as Y from 'yjs';\nimport {\n type Block,\n CRDT_DOC_VERSION,\n CRDT_RECORD_MAP_KEY,\n CRDT_STATE_MAP_KEY,\n CRDT_STATE_MAP_SAVED_AT_KEY,\n CRDT_STATE_MAP_SAVED_BY_KEY,\n CRDT_STATE_MAP_VERSION_KEY,\n} from './types.js';\nimport { blockToYMap, deltaUpdateYText, yMapToBlock } from './block-converter.js';\nimport { BlockTypeRegistry } from './block-type-registry.js';\n\nexport class DocumentManager {\n private registry: BlockTypeRegistry;\n\n constructor(registry?: BlockTypeRegistry) {\n this.registry = registry ?? BlockTypeRegistry.createFallback();\n }\n\n /**\n * Update the registry (e.g., after fetching block types from the API).\n */\n setRegistry(registry: BlockTypeRegistry): void {\n this.registry = registry;\n }\n\n /**\n * Get the current block type registry.\n */\n getRegistry(): BlockTypeRegistry {\n return this.registry;\n }\n\n /**\n * Create a new Y.Doc initialised with Gutenberg's expected structure.\n */\n createDoc(): Y.Doc {\n const doc = new Y.Doc();\n\n doc.transact(() => {\n // Initialise state map only — matches Gutenberg's initializeYjsDoc.\n // Do NOT pre-populate the document map with empty Y.Text/Y.Array.\n // Those keys will be created on demand when content is first set,\n // or populated from a remote peer's state via sync.\n // Pre-creating them would cause CRDT merge conflicts during sync\n // (two competing values for the same Y.Map key).\n const stateMap = doc.getMap(CRDT_STATE_MAP_KEY);\n stateMap.set(CRDT_STATE_MAP_VERSION_KEY, CRDT_DOC_VERSION);\n });\n\n return doc;\n }\n\n /**\n * Get the root 'document' Y.Map.\n */\n getDocumentMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(CRDT_RECORD_MAP_KEY);\n }\n\n /**\n * Get the root 'state' Y.Map.\n */\n getStateMap(doc: Y.Doc): Y.Map<unknown> {\n return doc.getMap(CRDT_STATE_MAP_KEY);\n }\n\n /**\n * Read the title as a plain string.\n */\n getTitle(doc: Y.Doc): string {\n const documentMap = this.getDocumentMap(doc);\n const title = documentMap.get('title');\n if (title instanceof Y.Text) {\n return title.toJSON();\n }\n return '';\n }\n\n /**\n * Set the title (replaces full Y.Text content).\n */\n setTitle(doc: Y.Doc, title: string): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const ytext = documentMap.get('title');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, title);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, title);\n documentMap.set('title', newYText);\n }\n });\n }\n\n /**\n * Get all blocks as plain Block[] objects.\n */\n getBlocks(doc: Y.Doc): Block[] {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!blocksArray) {\n return [];\n }\n\n const blocks: Block[] = [];\n for (let i = 0; i < blocksArray.length; i++) {\n blocks.push(yMapToBlock(blocksArray.get(i)));\n }\n return blocks;\n }\n\n /**\n * Set blocks from plain Block[] objects (replaces all existing blocks).\n */\n setBlocks(doc: Y.Doc, blocks: Block[]): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n let blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>> | undefined;\n\n if (!blocksArray) {\n blocksArray = new Y.Array<Y.Map<unknown>>();\n documentMap.set('blocks', blocksArray);\n }\n\n // Clear existing blocks\n if (blocksArray.length > 0) {\n blocksArray.delete(0, blocksArray.length);\n }\n\n // Insert new blocks\n const ymaps = blocks.map((block) => blockToYMap(block, this.registry));\n blocksArray.push(ymaps);\n });\n }\n\n /**\n * Get a single block by index. Supports dot notation for nested blocks\n * (e.g., \"2.1\" means inner block at index 1 of top-level block at index 2).\n */\n getBlockByIndex(doc: Y.Doc, index: string): Block | null {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n return null;\n }\n return yMapToBlock(ymap);\n }\n\n /**\n * Update a block's content and/or attributes at a given index.\n */\n updateBlock(\n doc: Y.Doc,\n index: string,\n changes: { content?: string; attributes?: Record<string, unknown> },\n ): void {\n doc.transact(() => {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n return;\n }\n\n const blockName = ymap.get('name') as string;\n const attrMap = ymap.get('attributes') as Y.Map<unknown>;\n\n if (changes.content !== undefined) {\n // 'content' is the primary rich-text attribute for most blocks\n if (this.registry.isRichTextAttribute(blockName, 'content')) {\n const ytext = attrMap.get('content');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, changes.content);\n } else {\n // Create Y.Text if it doesn't exist yet\n const newYText = new Y.Text();\n newYText.insert(0, changes.content);\n attrMap.set('content', newYText);\n }\n } else {\n attrMap.set('content', changes.content);\n }\n }\n\n if (changes.attributes) {\n for (const [key, value] of Object.entries(changes.attributes)) {\n if (this.registry.isRichTextAttribute(blockName, key) && typeof value === 'string') {\n const existing = attrMap.get(key);\n if (existing instanceof Y.Text) {\n deltaUpdateYText(existing, value);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, value);\n attrMap.set(key, newYText);\n }\n } else {\n attrMap.set(key, value);\n }\n }\n }\n });\n }\n\n /**\n * Insert a block at the given position in the top-level blocks array.\n */\n insertBlock(doc: Y.Doc, position: number, block: Block): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n let blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!blocksArray) {\n blocksArray = new Y.Array<Y.Map<unknown>>();\n documentMap.set('blocks', blocksArray);\n }\n const ymap = blockToYMap(block, this.registry);\n blocksArray.insert(position, [ymap]);\n });\n }\n\n /**\n * Remove `count` blocks starting at `startIndex`.\n */\n removeBlocks(doc: Y.Doc, startIndex: number, count: number): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>>;\n blocksArray.delete(startIndex, count);\n });\n }\n\n /**\n * Insert a block as an inner block of a parent block.\n */\n insertInnerBlock(doc: Y.Doc, parentIndex: string, position: number, block: Block): void {\n doc.transact(() => {\n const parentYMap = this._resolveBlockYMap(doc, parentIndex);\n if (!parentYMap) {\n throw new Error(`Block not found at index ${parentIndex}`);\n }\n\n let innerBlocksArray = parentYMap.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!innerBlocksArray) {\n innerBlocksArray = new Y.Array<Y.Map<unknown>>();\n parentYMap.set('innerBlocks', innerBlocksArray);\n }\n\n const ymap = blockToYMap(block, this.registry);\n innerBlocksArray.insert(position, [ymap]);\n });\n }\n\n /**\n * Remove inner blocks from a parent block.\n */\n removeInnerBlocks(doc: Y.Doc, parentIndex: string, startIndex: number, count: number): void {\n doc.transact(() => {\n const parentYMap = this._resolveBlockYMap(doc, parentIndex);\n if (!parentYMap) {\n throw new Error(`Block not found at index ${parentIndex}`);\n }\n\n const innerBlocksArray = parentYMap.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (!innerBlocksArray) {\n throw new Error(`Block at ${parentIndex} has no inner blocks`);\n }\n\n innerBlocksArray.delete(startIndex, count);\n });\n }\n\n /**\n * Move a block from one position to another.\n */\n moveBlock(doc: Y.Doc, fromIndex: number, toIndex: number): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>>;\n\n // Read the block at fromIndex as a plain object, then re-insert\n const block = yMapToBlock(blocksArray.get(fromIndex));\n blocksArray.delete(fromIndex, 1);\n\n // Adjust target index if removing shifts it\n const adjustedIndex = fromIndex < toIndex ? toIndex - 1 : toIndex;\n const ymap = blockToYMap(block, this.registry);\n blocksArray.insert(adjustedIndex, [ymap]);\n });\n }\n\n /**\n * Mark the document as saved by updating the state map.\n */\n markSaved(doc: Y.Doc): void {\n doc.transact(() => {\n const stateMap = this.getStateMap(doc);\n stateMap.set(CRDT_STATE_MAP_SAVED_AT_KEY, Date.now());\n stateMap.set(CRDT_STATE_MAP_SAVED_BY_KEY, doc.clientID);\n });\n }\n\n /**\n * Get the content field as a string.\n */\n getContent(doc: Y.Doc): string {\n const documentMap = this.getDocumentMap(doc);\n const content = documentMap.get('content');\n if (content instanceof Y.Text) {\n return content.toJSON();\n }\n return '';\n }\n\n /**\n * Set the content field.\n */\n setContent(doc: Y.Doc, content: string): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const ytext = documentMap.get('content');\n if (ytext instanceof Y.Text) {\n deltaUpdateYText(ytext, content);\n } else {\n const newYText = new Y.Text();\n newYText.insert(0, content);\n documentMap.set('content', newYText);\n }\n });\n }\n\n /**\n * Get a post property from the document map.\n */\n getProperty(doc: Y.Doc, key: string): unknown {\n const documentMap = this.getDocumentMap(doc);\n const value = documentMap.get(key);\n if (value instanceof Y.Text) {\n return value.toJSON();\n }\n return value;\n }\n\n /**\n * Set a post property in the document map.\n */\n setProperty(doc: Y.Doc, key: string, value: unknown): void {\n doc.transact(() => {\n const documentMap = this.getDocumentMap(doc);\n const existing = documentMap.get(key);\n if (existing instanceof Y.Text && typeof value === 'string') {\n deltaUpdateYText(existing, value);\n } else {\n documentMap.set(key, value);\n }\n });\n }\n\n /**\n * Get the raw Y.Text for a block attribute.\n * Returns null if the block doesn't exist, the attribute doesn't exist,\n * or the attribute is not a Y.Text (i.e., not a rich-text attribute).\n */\n getBlockAttributeYText(doc: Y.Doc, index: string, attrName: string): Y.Text | null {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) return null;\n const attrMap = ymap.get('attributes') as Y.Map<unknown> | undefined;\n if (!attrMap) return null;\n const attr = attrMap.get(attrName);\n return attr instanceof Y.Text ? attr : null;\n }\n\n /**\n * Get the raw Y.Text for a block's content attribute.\n * Returns null if the block or content attribute doesn't exist.\n */\n getBlockContentYText(doc: Y.Doc, index: string): Y.Text | null {\n return this.getBlockAttributeYText(doc, index, 'content');\n }\n\n /**\n * Set the noteId in a block's metadata attribute.\n * Metadata is a plain JS object stored in the block's attribute Y.Map.\n * Performs read-modify-write to preserve any existing metadata keys.\n */\n setBlockNoteId(doc: Y.Doc, index: string, noteId: number): void {\n doc.transact(() => {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n throw new Error(`Block not found at index ${index}`);\n }\n\n const attrMap = ymap.get('attributes') as Y.Map<unknown>;\n const currentMetadata =\n (attrMap.get('metadata') as Record<string, unknown> | undefined) ?? {};\n attrMap.set('metadata', { ...currentMetadata, noteId });\n });\n }\n\n /**\n * Remove the noteId from a block's metadata attribute.\n * If noteId was the only key, the metadata key is deleted entirely.\n * If the block has no metadata or no noteId, this is a no-op.\n */\n removeBlockNoteId(doc: Y.Doc, index: string): void {\n doc.transact(() => {\n const ymap = this._resolveBlockYMap(doc, index);\n if (!ymap) {\n throw new Error(`Block not found at index ${index}`);\n }\n\n const attrMap = ymap.get('attributes') as Y.Map<unknown>;\n const currentMetadata = attrMap.get('metadata') as Record<string, unknown> | undefined;\n\n if (!currentMetadata || !('noteId' in currentMetadata)) {\n return;\n }\n\n const { noteId: _, ...rest } = currentMetadata;\n if (Object.keys(rest).length === 0) {\n attrMap.delete('metadata');\n } else {\n attrMap.set('metadata', rest);\n }\n });\n }\n\n /**\n * Resolve a dot-notation index to a Y.Map block reference.\n * E.g., \"2\" → top-level block 2, \"2.1\" → inner block 1 of block 2.\n */\n private _resolveBlockYMap(doc: Y.Doc, index: string): Y.Map<unknown> | null {\n const parts = index.split('.').map(Number);\n const documentMap = this.getDocumentMap(doc);\n const blocksArray = documentMap.get('blocks') as Y.Array<Y.Map<unknown>>;\n\n if (parts.length === 0 || isNaN(parts[0])) {\n return null;\n }\n\n let current: Y.Map<unknown> | null = null;\n let currentArray: Y.Array<Y.Map<unknown>> = blocksArray;\n\n for (const part of parts) {\n if (part < 0 || part >= currentArray.length) {\n return null;\n }\n current = currentArray.get(part);\n // For next iteration, if there are more parts, descend into innerBlocks\n const innerBlocks = current.get('innerBlocks') as Y.Array<Y.Map<unknown>> | undefined;\n if (innerBlocks) {\n currentArray = innerBlocks;\n }\n }\n\n return current;\n }\n}\n","import type {\n WordPressConfig,\n WPBlockType,\n WPMediaItem,\n WPNote,\n WPPost,\n WPTerm,\n WPUser,\n SyncPayload,\n SyncResponse,\n} from './types.js';\n\n/**\n * WordPress REST API client using Application Password (HTTP Basic Auth).\n *\n * Uses native fetch() — requires Node.js 18+.\n */\nexport class WordPressApiClient {\n private baseUrl: string;\n private authHeader: string;\n\n constructor(config: WordPressConfig) {\n // Normalise URL: strip trailing slash(es)\n const siteUrl = config.siteUrl.replace(/\\/+$/, '');\n this.baseUrl = `${siteUrl}/wp-json`;\n this.authHeader = `Basic ${btoa(config.username + ':' + config.appPassword)}`;\n }\n\n /**\n * Validate the connection by fetching the current user.\n * Tests both auth and API availability.\n */\n async validateConnection(): Promise<WPUser> {\n return this.getCurrentUser();\n }\n\n /**\n * Check that the sync endpoint exists.\n * POSTs an empty rooms array to verify the endpoint responds.\n */\n async validateSyncEndpoint(): Promise<void> {\n await this.sendSyncUpdate({ rooms: [] });\n }\n\n /**\n * Fetch the WordPress version from the REST API root.\n *\n * Returns the version string, or `'unknown'` if it could not be\n * determined (e.g. the endpoint is unavailable or the field is missing).\n * Never throws — callers decide how to act on the result.\n */\n async getWordPressVersion(): Promise<string> {\n let data: { version?: string };\n try {\n data = await this.apiFetch<{ version?: string }>('/');\n } catch {\n return 'unknown';\n }\n\n const version = data.version;\n if (typeof version !== 'string' || version.trim() === '') {\n return 'unknown';\n }\n\n return version;\n }\n\n /**\n * Get the current authenticated user.\n * GET /wp/v2/users/me\n */\n async getCurrentUser(): Promise<WPUser> {\n return this.apiFetch<WPUser>('/wp/v2/users/me');\n }\n\n /**\n * List posts with optional filters.\n * GET /wp/v2/posts?status=...&search=...&per_page=...&context=edit\n */\n async listPosts(options?: {\n status?: string;\n search?: string;\n perPage?: number;\n }): Promise<WPPost[]> {\n const params = new URLSearchParams({ context: 'edit' });\n\n if (options?.status) {\n params.set('status', options.status);\n }\n if (options?.search) {\n params.set('search', options.search);\n }\n if (options?.perPage !== undefined) {\n params.set('per_page', String(options.perPage));\n }\n\n return this.apiFetch<WPPost[]>(`/wp/v2/posts?${params.toString()}`);\n }\n\n /**\n * Get a single post by ID.\n * GET /wp/v2/posts/{id}?context=edit\n */\n async getPost(id: number): Promise<WPPost> {\n return this.apiFetch<WPPost>(`/wp/v2/posts/${id}?context=edit`);\n }\n\n /**\n * Create a new post.\n * POST /wp/v2/posts\n */\n async createPost(data: { title?: string; content?: string; status?: string }): Promise<WPPost> {\n return this.apiFetch<WPPost>('/wp/v2/posts', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n /**\n * Fetch all registered block types from the WordPress site.\n * GET /wp/v2/block-types?context=edit\n */\n async getBlockTypes(): Promise<WPBlockType[]> {\n return this.apiFetch<WPBlockType[]>('/wp/v2/block-types?context=edit');\n }\n\n /**\n * Upload a file to the WordPress media library.\n * POST /wp/v2/media (multipart/form-data)\n */\n async uploadMedia(\n fileData: Buffer,\n fileName: string,\n mimeType: string,\n options?: { altText?: string; caption?: string; title?: string },\n ): Promise<WPMediaItem> {\n const formData = new FormData();\n const blob = new Blob([fileData], { type: mimeType });\n formData.append('file', blob, fileName);\n\n if (options?.title) formData.append('title', options.title);\n if (options?.altText) formData.append('alt_text', options.altText);\n if (options?.caption) formData.append('caption', options.caption);\n\n return this.apiFetch<WPMediaItem>('/wp/v2/media', {\n method: 'POST',\n body: formData,\n });\n }\n\n /**\n * Update an existing post's fields.\n * POST /wp/v2/posts/{id}?context=edit\n */\n async updatePost(id: number, data: Record<string, unknown>): Promise<WPPost> {\n return this.apiFetch<WPPost>(`/wp/v2/posts/${id}?context=edit`, {\n method: 'POST',\n body: JSON.stringify(data),\n });\n }\n\n /**\n * List taxonomy terms (categories or tags) with optional search filter.\n * GET /wp/v2/{categories|tags}\n */\n async listTerms(\n taxonomy: 'categories' | 'tags',\n options?: { search?: string; perPage?: number },\n ): Promise<WPTerm[]> {\n const params = new URLSearchParams({\n per_page: String(options?.perPage ?? 100),\n orderby: 'count',\n order: 'desc',\n });\n if (options?.search) {\n params.set('search', options.search);\n }\n return this.apiFetch<WPTerm[]>(`/wp/v2/${taxonomy}?${params.toString()}`);\n }\n\n /**\n * Search for taxonomy terms (categories or tags) by name.\n * GET /wp/v2/{categories|tags}?search=...\n */\n async searchTerms(taxonomy: 'categories' | 'tags', search: string): Promise<WPTerm[]> {\n const params = new URLSearchParams({ search, per_page: '100' });\n return this.apiFetch<WPTerm[]>(`/wp/v2/${taxonomy}?${params.toString()}`);\n }\n\n /**\n * Create a new taxonomy term (category or tag).\n * POST /wp/v2/{categories|tags}\n */\n async createTerm(taxonomy: 'categories' | 'tags', name: string): Promise<WPTerm> {\n return this.apiFetch<WPTerm>(`/wp/v2/${taxonomy}`, {\n method: 'POST',\n body: JSON.stringify({ name }),\n });\n }\n\n /**\n * Fetch taxonomy terms by IDs (for resolving IDs to names).\n * GET /wp/v2/{categories|tags}?include=...\n */\n async getTerms(taxonomy: 'categories' | 'tags', ids: number[]): Promise<WPTerm[]> {\n if (ids.length === 0) return [];\n const params = new URLSearchParams({\n include: ids.join(','),\n per_page: String(ids.length),\n });\n return this.apiFetch<WPTerm[]>(`/wp/v2/${taxonomy}?${params.toString()}`);\n }\n\n /**\n * Check whether the site supports notes (block comments).\n * GET /wp/v2/comments?type=note&per_page=1\n * Returns true if the endpoint accepts type=note, false if the endpoint\n * rejects the type parameter (400) or doesn't exist (404).\n * Other errors (auth, server) are re-thrown so callers get actionable errors.\n */\n async checkNotesSupport(): Promise<boolean> {\n try {\n await this.apiFetch<unknown>('/wp/v2/comments?type=note&per_page=1');\n return true;\n } catch (err) {\n if (err instanceof WordPressApiError && (err.status === 400 || err.status === 404)) {\n return false;\n }\n throw err;\n }\n }\n\n /**\n * List all notes (block comments) for a given post.\n * Paginates automatically (100 per page, the WP REST API maximum).\n */\n async listNotes(postId: number): Promise<WPNote[]> {\n const perPage = 100;\n const allNotes: WPNote[] = [];\n let page = 1;\n\n for (;;) {\n const params = new URLSearchParams({\n post: String(postId),\n type: 'note',\n context: 'edit',\n per_page: String(perPage),\n page: String(page),\n });\n\n const notes = await this.apiFetch<WPNote[]>(`/wp/v2/comments?${params.toString()}`);\n allNotes.push(...notes);\n\n if (notes.length < perPage) break;\n page++;\n }\n\n return allNotes;\n }\n\n /**\n * Create a new note (block comment) on a post.\n * POST /wp/v2/comments\n */\n async createNote(data: { post: number; content: string; parent?: number }): Promise<WPNote> {\n return this.apiFetch<WPNote>('/wp/v2/comments', {\n method: 'POST',\n body: JSON.stringify({\n post: data.post,\n content: data.content,\n type: 'note',\n ...(data.parent ? { parent: data.parent } : {}),\n }),\n });\n }\n\n /**\n * Update an existing note's content.\n * POST /wp/v2/comments/{noteId}\n */\n async updateNote(noteId: number, data: { content: string }): Promise<WPNote> {\n return this.apiFetch<WPNote>(`/wp/v2/comments/${noteId}`, {\n method: 'POST',\n body: JSON.stringify({ content: data.content }),\n });\n }\n\n /**\n * Delete a note permanently.\n * DELETE /wp/v2/comments/{noteId}?force=true\n */\n async deleteNote(noteId: number): Promise<void> {\n await this.apiFetch<unknown>(`/wp/v2/comments/${noteId}?force=true`, {\n method: 'DELETE',\n });\n }\n\n /**\n * Send a sync payload and receive response.\n * POST /wp-sync/v1/updates\n */\n async sendSyncUpdate(payload: SyncPayload): Promise<SyncResponse> {\n return this.apiFetch<SyncResponse>('/wp-sync/v1/updates', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n }\n\n /**\n * Produce a human-friendly error message for common failure modes.\n */\n private formatErrorMessage(path: string, status: number, body: string): string {\n if (status === 401 || status === 403) {\n return `Authentication failed. Check your username and Application Password. (HTTP ${status})`;\n }\n\n if (status === 404 && path.startsWith('/wp-sync/')) {\n return (\n 'Collaborative editing is not enabled. ' +\n 'Enable it in Settings \\u2192 Writing in your WordPress admin, then try again. ' +\n '(Requires WordPress 7.0 or later.)'\n );\n }\n\n return `WordPress API error ${status}: ${body}`;\n }\n\n /**\n * Internal fetch helper with auth and error handling.\n */\n private async apiFetch<T>(path: string, options?: RequestInit): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: this.authHeader,\n Accept: 'application/json',\n };\n\n // Add Content-Type for JSON requests (skip for FormData — fetch auto-sets the boundary)\n if (\n (options?.method === 'POST' || options?.method === 'PUT') &&\n !(options.body instanceof FormData)\n ) {\n headers['Content-Type'] = 'application/json';\n }\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...headers,\n ...(options?.headers as Record<string, string> | undefined),\n },\n });\n\n if (!response.ok) {\n let errorBody: string;\n try {\n errorBody = await response.text();\n } catch {\n errorBody = '(unable to read response body)';\n }\n\n const message = this.formatErrorMessage(path, response.status, errorBody);\n\n throw new WordPressApiError(message, response.status, errorBody);\n }\n\n return (await response.json()) as T;\n }\n}\n\n/**\n * Custom error class for WordPress API errors,\n * carrying the HTTP status and response body.\n */\nexport class WordPressApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly body: string,\n ) {\n super(message);\n this.name = 'WordPressApiError';\n }\n}\n","import type {\n SyncUpdate,\n SyncClientConfig,\n SyncUpdateType,\n AwarenessState,\n LocalAwarenessState,\n} from './types.js';\nimport type { WordPressApiClient } from './api-client.js';\n\nexport type SyncStatus = 'connecting' | 'connected' | 'disconnected' | 'error';\n\nexport interface SyncCallbacks {\n /** Process an incoming update. Return a SyncUpdate to queue (e.g. sync_step2), or null. */\n onUpdate: (update: SyncUpdate) => SyncUpdate | null;\n /** Called when awareness state changes. */\n onAwareness: (state: AwarenessState) => void;\n /** Called when connection status changes. The error is provided on 'error' status. */\n onStatusChange: (status: SyncStatus, error?: Error) => void;\n /** Called when the server requests compaction; must return a compaction update. */\n onCompactionRequested: () => SyncUpdate;\n /** Return the current local awareness state, or null if disconnected. */\n getAwarenessState: () => LocalAwarenessState;\n}\n\n/** Room-specific callbacks (everything except the global onStatusChange). */\nexport type RoomCallbacks = Omit<SyncCallbacks, 'onStatusChange'>;\n\ninterface RoomState {\n room: string;\n clientId: number;\n endCursor: number;\n updateQueue: SyncUpdate[];\n queuePaused: boolean;\n hasCollaborators: boolean;\n callbacks: RoomCallbacks;\n}\n\n/**\n * HTTP polling sync client that maintains the Gutenberg sync loop.\n *\n * Supports multiple rooms, each with their own state, while sending\n * all rooms in a single HTTP request per poll cycle.\n *\n * Uses chained setTimeout (not setInterval) so polling interval\n * can adapt dynamically to collaborator presence and errors.\n */\nexport class SyncClient {\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private currentBackoff: number;\n private isPolling: boolean = false;\n private pollInProgress: boolean = false;\n private flushRequested: boolean = false;\n\n private rooms = new Map<string, RoomState>();\n private onStatusChange: ((status: SyncStatus, error?: Error) => void) | null = null;\n private firstPollResolve: (() => void) | null = null;\n\n constructor(\n private apiClient: WordPressApiClient,\n private config: SyncClientConfig,\n ) {\n this.currentBackoff = config.pollingInterval;\n }\n\n /**\n * Returns a promise that resolves after the first poll cycle completes.\n * Used to wait for initial sync state before loading content.\n */\n waitForFirstPoll(): Promise<void> {\n return new Promise<void>((resolve) => {\n this.firstPollResolve = resolve;\n });\n }\n\n /**\n * Start the polling loop for a room.\n *\n * This is a backward-compatible wrapper that sets the global onStatusChange\n * callback and adds the room via addRoom(), then starts polling if not already active.\n *\n * @param room Room identifier, e.g. 'postType/post:123'\n * @param clientId Y.Doc clientID\n * @param initialUpdates Initial sync updates to send (sync_step1)\n * @param callbacks Event callbacks\n */\n start(\n room: string,\n clientId: number,\n initialUpdates: SyncUpdate[],\n callbacks: SyncCallbacks,\n ): void {\n this.onStatusChange = callbacks.onStatusChange;\n\n const roomCallbacks: RoomCallbacks = {\n onUpdate: callbacks.onUpdate,\n onAwareness: callbacks.onAwareness,\n onCompactionRequested: callbacks.onCompactionRequested,\n getAwarenessState: callbacks.getAwarenessState,\n };\n this.addRoom(room, clientId, initialUpdates, roomCallbacks);\n\n if (!this.isPolling) {\n this.currentBackoff = this.config.pollingInterval;\n this.isPolling = true;\n this.onStatusChange('connecting');\n this.pollTimer = setTimeout(() => void this.poll(), 0);\n }\n }\n\n /**\n * Add a room to the sync loop.\n *\n * @param room Room identifier\n * @param clientId Y.Doc clientID for this room\n * @param initialUpdates Initial sync updates to send (sync_step1)\n * @param callbacks Room-specific event callbacks\n */\n addRoom(\n room: string,\n clientId: number,\n initialUpdates: SyncUpdate[],\n callbacks: RoomCallbacks,\n ): void {\n if (this.rooms.has(room)) {\n throw new Error(`Room '${room}' is already registered`);\n }\n this.rooms.set(room, {\n room,\n clientId,\n endCursor: 0,\n updateQueue: [...initialUpdates],\n queuePaused: true,\n hasCollaborators: false,\n callbacks,\n });\n }\n\n /**\n * Remove a room from the sync loop.\n * If this was the last room, stops polling entirely.\n */\n removeRoom(room: string): void {\n this.rooms.delete(room);\n if (this.rooms.size === 0) {\n this.stop();\n }\n }\n\n /**\n * Stop the polling loop.\n */\n stop(): void {\n this.isPolling = false;\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.rooms.clear();\n this.onStatusChange?.('disconnected');\n this.onStatusChange = null;\n }\n\n /**\n * Flush the outgoing queue by triggering an immediate poll.\n *\n * If a poll is already in progress, sets a flag so that another poll\n * is triggered immediately after the current one completes. This avoids\n * concurrent poll execution while ensuring the flush is honoured.\n */\n flushQueue(): void {\n if (!this.isPolling) return;\n\n if (this.pollInProgress) {\n // A poll is already running — request a follow-up poll when it finishes\n this.flushRequested = true;\n return;\n }\n\n // Cancel the scheduled timer and poll immediately\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.pollTimer = setTimeout(() => void this.poll(), 0);\n }\n\n /**\n * Add an update to the outgoing queue for a specific room.\n */\n queueUpdate(room: string, update: SyncUpdate): void {\n const state = this.rooms.get(room);\n if (!state) {\n throw new Error(`Room '${room}' is not registered`);\n }\n state.updateQueue.push(update);\n }\n\n /**\n * Get sync status info, aggregated across all rooms.\n */\n getStatus(): {\n isPolling: boolean;\n hasCollaborators: boolean;\n queuePaused: boolean;\n endCursor: number;\n queueSize: number;\n } {\n let hasCollaborators = false;\n let queuePaused = false;\n let totalQueueSize = 0;\n let maxEndCursor = 0;\n\n for (const state of this.rooms.values()) {\n if (state.hasCollaborators) hasCollaborators = true;\n if (state.queuePaused) queuePaused = true;\n totalQueueSize += state.updateQueue.length;\n if (state.endCursor > maxEndCursor) maxEndCursor = state.endCursor;\n }\n\n return {\n isPolling: this.isPolling,\n hasCollaborators,\n queuePaused,\n endCursor: maxEndCursor,\n queueSize: totalQueueSize,\n };\n }\n\n /**\n * Execute one poll cycle.\n */\n private async poll(): Promise<void> {\n if (!this.isPolling || this.rooms.size === 0) return;\n if (this.pollInProgress) return;\n\n this.pollInProgress = true;\n this.flushRequested = false;\n\n // Drain all rooms' queues and build payload\n const drainedQueues = new Map<string, SyncUpdate[]>();\n const roomPayloads = [];\n\n for (const [name, state] of this.rooms) {\n const updates = state.updateQueue.splice(0);\n drainedQueues.set(name, updates);\n roomPayloads.push({\n room: name,\n client_id: state.clientId,\n after: state.endCursor,\n awareness: state.callbacks.getAwarenessState(),\n updates,\n });\n }\n\n try {\n const response = await this.apiClient.sendSyncUpdate({ rooms: roomPayloads });\n\n // Success — reset backoff based on collaborator presence\n this.currentBackoff = this.anyCollaborators()\n ? this.config.pollingIntervalWithCollaborators\n : this.config.pollingInterval;\n\n this.onStatusChange?.('connected');\n this.processResponse(response);\n\n // Re-check after processing (collaborators may have changed)\n this.currentBackoff = this.anyCollaborators()\n ? this.config.pollingIntervalWithCollaborators\n : this.config.pollingInterval;\n\n if (this.firstPollResolve) {\n this.firstPollResolve();\n this.firstPollResolve = null;\n }\n } catch (error) {\n // Restore un-sent updates for ALL rooms (excluding stale compaction updates)\n for (const [name, updates] of drainedQueues) {\n const state = this.rooms.get(name);\n if (state) {\n const restorable = updates.filter((u) => u.type !== ('compaction' as SyncUpdateType));\n state.updateQueue.unshift(...restorable);\n }\n }\n\n this.onStatusChange?.('error', error instanceof Error ? error : undefined);\n this.currentBackoff = Math.min(this.currentBackoff * 2, this.config.maxErrorBackoff);\n }\n\n this.pollInProgress = false;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- flushQueue() may set this during the await\n if (this.flushRequested) {\n this.flushRequested = false;\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.pollTimer = setTimeout(() => void this.poll(), 0);\n } else {\n this.scheduleNextPoll();\n }\n }\n\n /**\n * Check if any room has collaborators.\n */\n private anyCollaborators(): boolean {\n for (const state of this.rooms.values()) {\n if (state.hasCollaborators) return true;\n }\n return false;\n }\n\n /**\n * Schedule the next poll using the current interval / backoff.\n */\n private scheduleNextPoll(): void {\n if (!this.isPolling) {\n return;\n }\n\n this.pollTimer = setTimeout(() => void this.poll(), this.currentBackoff);\n }\n\n /**\n * Process a sync response from the server.\n */\n private processResponse(response: {\n rooms: Array<{\n room: string;\n end_cursor: number;\n awareness: AwarenessState;\n updates: SyncUpdate[];\n should_compact?: boolean;\n }>;\n }): void {\n for (const roomData of response.rooms) {\n const state = this.rooms.get(roomData.room);\n if (!state) continue;\n\n // Update end cursor\n state.endCursor = roomData.end_cursor;\n\n // Process awareness — detect collaborators\n state.callbacks.onAwareness(roomData.awareness);\n\n const otherClients = Object.keys(roomData.awareness).filter(\n (id) => Number(id) !== state.clientId && roomData.awareness[id] !== null,\n );\n const hadCollaborators = state.hasCollaborators;\n state.hasCollaborators = otherClients.length > 0;\n\n if (state.hasCollaborators && !hadCollaborators) {\n state.queuePaused = false;\n }\n\n // Process incoming updates\n for (const update of roomData.updates) {\n const reply = state.callbacks.onUpdate(update);\n if (reply) {\n state.updateQueue.push(reply);\n }\n }\n\n // Handle compaction\n if (roomData.should_compact) {\n const compactionUpdate = state.callbacks.onCompactionRequested();\n state.updateQueue.push(compactionUpdate);\n }\n }\n }\n}\n","/**\n * WordPress REST API and sync protocol types.\n *\n * These types match the wire format used by the Gutenberg HTTP polling\n * sync provider at POST /wp-sync/v1/updates.\n */\n\n// --- Sync Protocol Types ---\n\nexport enum SyncUpdateType {\n SYNC_STEP_1 = 'sync_step1',\n SYNC_STEP_2 = 'sync_step2',\n UPDATE = 'update',\n COMPACTION = 'compaction',\n}\n\n/** A single typed update with base64-encoded Yjs binary data. */\nexport interface SyncUpdate {\n type: SyncUpdateType;\n data: string; // base64-encoded Yjs V2 update\n}\n\n/** Awareness state: null means disconnected. */\nexport type LocalAwarenessState = object | null;\n\n/** Server-side awareness: map of clientId (as string) → state object. */\nexport type AwarenessState = Record<string, LocalAwarenessState>;\n\n// --- Client → Server ---\n\nexport interface SyncEnvelopeFromClient {\n room: string;\n client_id: number;\n after: number;\n awareness: LocalAwarenessState;\n updates: SyncUpdate[];\n}\n\nexport interface SyncPayload {\n rooms: SyncEnvelopeFromClient[];\n}\n\n// --- Server → Client ---\n\nexport interface SyncEnvelopeFromServer {\n room: string;\n end_cursor: number;\n awareness: AwarenessState;\n updates: SyncUpdate[];\n should_compact?: boolean;\n compaction_request?: SyncUpdate[]; // deprecated\n}\n\nexport interface SyncResponse {\n rooms: SyncEnvelopeFromServer[];\n}\n\n// --- WordPress REST API Types ---\n\n/** WordPress post as returned by the REST API (subset of fields we care about). */\nexport interface WPPost {\n id: number;\n title: { rendered: string; raw?: string };\n content: { rendered: string; raw?: string };\n excerpt: { rendered: string; raw?: string };\n status: string;\n type: string;\n slug: string;\n author: number;\n date: string | null;\n modified: string;\n categories?: number[];\n tags?: number[];\n featured_media?: number;\n comment_status?: string;\n ping_status?: string;\n sticky?: boolean;\n format?: string;\n meta?: Record<string, unknown>;\n}\n\n/** WordPress taxonomy term (category or tag) as returned by the REST API. */\nexport interface WPTerm {\n id: number;\n name: string;\n slug: string;\n taxonomy: string;\n count?: number;\n parent?: number;\n}\n\n/** WordPress user as returned by /wp/v2/users/me. */\nexport interface WPUser {\n id: number;\n name: string | null;\n slug: string;\n avatar_urls: Record<string, string> | null;\n}\n\n// --- Block Type API Types ---\n\n/** A single attribute definition from the block type schema. */\nexport interface WPBlockTypeAttribute {\n type: string; // \"rich-text\", \"string\", \"boolean\", \"number\", \"integer\", \"array\", \"object\"\n source?: string; // \"rich-text\", \"html\", \"attribute\", \"text\", \"query\"\n default?: unknown;\n role?: string;\n}\n\n/** A block type as returned by GET /wp/v2/block-types. */\nexport interface WPBlockType {\n name: string;\n title?: string;\n attributes: Record<string, WPBlockTypeAttribute> | null;\n /** Block types this block can be nested inside. Null/empty = any parent. */\n parent?: string[] | null;\n /** Ancestor blocks (more flexible than parent — any ancestor, not just direct). */\n ancestor?: string[] | null;\n /** Block types allowed as direct children. Null = any, string[] = restricted list. */\n allowed_blocks?: string[] | null;\n /** Block supports object. We extract `allowedBlocks` (boolean = InnerBlocks capability). */\n supports?: { allowedBlocks?: boolean; [key: string]: unknown } | null;\n}\n\n// --- Media API Types ---\n\n/** WordPress media item as returned by POST /wp/v2/media. */\nexport interface WPMediaItem {\n id: number;\n source_url: string;\n title: { rendered: string; raw?: string };\n caption: { rendered: string; raw?: string };\n alt_text: string;\n mime_type: string;\n media_details: {\n width?: number;\n height?: number;\n sizes?: Record<string, { source_url: string; width: number; height: number }>;\n };\n}\n\n// --- Notes (Block Comments) API Types ---\n\n/** WordPress note (comment_type = 'note') as returned by /wp/v2/comments. */\nexport interface WPNote {\n id: number;\n post: number;\n parent: number; // 0 = top-level, >0 = reply to that note ID\n author: number;\n author_name: string;\n date: string;\n content: { rendered: string; raw?: string };\n status: string; // 'hold', 'approved', etc.\n type: string; // always 'note'\n}\n\n// --- Connection Config ---\n\nexport interface WordPressConfig {\n siteUrl: string;\n username: string;\n appPassword: string;\n}\n\n// --- Sync Client Config ---\n\nexport interface SyncClientConfig {\n /** Polling interval in ms when editing solo. */\n pollingInterval: number;\n /** Polling interval in ms when collaborators are present. */\n pollingIntervalWithCollaborators: number;\n /** Max exponential backoff in ms on error. */\n maxErrorBackoff: number;\n}\n\nexport const DEFAULT_SYNC_CONFIG: SyncClientConfig = {\n pollingInterval: 1000,\n pollingIntervalWithCollaborators: 250,\n maxErrorBackoff: 30_000,\n};\n","/**\n * Yjs sync protocol helpers for the HTTP polling transport.\n *\n * Gutenberg 22.8+ uses a mixed V1/V2 encoding approach:\n * - Sync step1/step2 use y-protocols' standard encoding (V1 internally).\n * Gutenberg calls syncProtocol.readSyncMessage() for both creating and\n * processing step2, which hardcodes Y.encodeStateAsUpdate/Y.applyUpdate (V1).\n * - Regular updates and compactions use Yjs V2 encoding.\n * Gutenberg captures changes via doc.on('updateV2') and applies with Y.applyUpdateV2().\n *\n * All binary data is base64-encoded for transport.\n */\nimport * as Y from 'yjs';\nimport * as syncProtocol from 'y-protocols/sync';\nimport * as encoding from 'lib0/encoding';\nimport * as decoding from 'lib0/decoding';\nimport { type SyncUpdate, SyncUpdateType } from '../wordpress/types.js';\n\n/**\n * Create a sync_step1 message announcing our state vector.\n * State vectors are encoding-format-agnostic (identical for V1 and V2).\n */\nexport function createSyncStep1(doc: Y.Doc): SyncUpdate {\n const encoder = encoding.createEncoder();\n syncProtocol.writeSyncStep1(encoder, doc);\n const data = encoding.toUint8Array(encoder);\n\n return {\n type: SyncUpdateType.SYNC_STEP_1,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Process an incoming sync_step1 and create a sync_step2 response.\n *\n * Reads the remote state vector from the step1 message and encodes\n * the missing updates as a step2 reply.\n *\n * Uses y-protocols' readSyncMessage which produces V1-encoded step2 data.\n * This matches Gutenberg's expectation — it also uses readSyncMessage\n * (and thus V1) for step2 processing.\n */\nexport function createSyncStep2(doc: Y.Doc, step1Data: Uint8Array): SyncUpdate {\n const decoder = decoding.createDecoder(step1Data);\n const encoder = encoding.createEncoder();\n\n // readSyncMessage reads the message type byte and the state vector,\n // then writes the appropriate response (step2) into the encoder.\n // Internally uses V1 encoding (Y.encodeStateAsUpdate), matching Gutenberg.\n syncProtocol.readSyncMessage(decoder, encoder, doc, 'sync');\n\n const data = encoding.toUint8Array(encoder);\n\n return {\n type: SyncUpdateType.SYNC_STEP_2,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Process an incoming sync update.\n *\n * For SYNC_STEP_1: generates a SYNC_STEP_2 response.\n * For SYNC_STEP_2: applies via y-protocols (V1 internally) and returns null.\n * For UPDATE / COMPACTION: applies the V2 update and returns null.\n *\n * Returns a response SyncUpdate if one is needed (e.g., step2 reply),\n * or null if no response is required.\n */\nexport function processIncomingUpdate(doc: Y.Doc, update: SyncUpdate): SyncUpdate | null {\n const rawData = base64ToUint8Array(update.data);\n\n switch (update.type) {\n case SyncUpdateType.SYNC_STEP_1: {\n // Respond with step2\n return createSyncStep2(doc, rawData);\n }\n\n case SyncUpdateType.SYNC_STEP_2: {\n // Apply step2 via y-protocols (V1 internally).\n // Gutenberg creates step2 using syncProtocol.readSyncMessage which\n // encodes with Y.encodeStateAsUpdate (V1), so we must also use\n // readSyncMessage to decode it (which calls Y.applyUpdate, V1).\n const decoder = decoding.createDecoder(rawData);\n const encoder = encoding.createEncoder();\n syncProtocol.readSyncMessage(decoder, encoder, doc, 'sync');\n return null;\n }\n\n case SyncUpdateType.UPDATE:\n case SyncUpdateType.COMPACTION: {\n // Apply V2 update directly (Gutenberg 22.8+ uses V2 encoding)\n Y.applyUpdateV2(doc, rawData, 'remote');\n return null;\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Create an update message from a Y.Doc change.\n * The raw bytes come from the doc's 'updateV2' event (V2 encoded).\n */\nexport function createUpdateFromChange(update: Uint8Array): SyncUpdate {\n return {\n type: SyncUpdateType.UPDATE,\n data: uint8ArrayToBase64(update),\n };\n}\n\n/**\n * Create a compaction update containing the full document state (V2 encoded).\n */\nexport function createCompactionUpdate(doc: Y.Doc): SyncUpdate {\n const data = Y.encodeStateAsUpdateV2(doc);\n return {\n type: SyncUpdateType.COMPACTION,\n data: uint8ArrayToBase64(data),\n };\n}\n\n/**\n * Encode a Uint8Array to a base64 string.\n */\nexport function uint8ArrayToBase64(data: Uint8Array): string {\n return Buffer.from(data).toString('base64');\n}\n\n/**\n * Decode a base64 string to a Uint8Array.\n */\nexport function base64ToUint8Array(base64: string): Uint8Array {\n return new Uint8Array(Buffer.from(base64, 'base64'));\n}\n","/**\n * Block parser: wraps @wordpress/block-serialization-default-parser to produce\n * normalised ParsedBlock[] from Gutenberg HTML, then converts to Block[].\n */\n\nimport { parse as wpParse } from '@wordpress/block-serialization-default-parser';\nimport type { RawParsedBlock, ParsedBlock } from './types.js';\nimport type { Block } from '../yjs/types.js';\n\n/**\n * Parse Gutenberg HTML content into normalised blocks.\n * - Null blockNames (freeform HTML) become 'core/freeform'\n * - Attributes are extracted from the block comment delimiters (attrs field)\n * - innerHTML is preserved as originalContent\n * - For common blocks, extract text content from innerHTML into attributes\n */\nexport function parseBlocks(html: string): ParsedBlock[] {\n const raw = wpParse(html) as RawParsedBlock[];\n return raw\n .filter((block) => block.blockName !== null || block.innerHTML.trim() !== '')\n .map(normaliseParsedBlock);\n}\n\n/**\n * Convert a ParsedBlock to a Block (adding clientId, mapping innerBlocks).\n */\nexport function parsedBlockToBlock(parsed: ParsedBlock): Block {\n return {\n name: parsed.name,\n clientId: crypto.randomUUID(),\n attributes: { ...parsed.attributes },\n innerBlocks: parsed.innerBlocks.map(parsedBlockToBlock),\n originalContent: parsed.originalContent,\n };\n}\n\nfunction normaliseParsedBlock(raw: RawParsedBlock): ParsedBlock {\n const blockName = raw.blockName ?? 'core/freeform';\n const commentAttrs = raw.attrs ?? {};\n const extractedAttrs = extractAttributesFromHTML(blockName, raw.innerHTML, commentAttrs);\n\n return {\n name: blockName,\n attributes: { ...commentAttrs, ...extractedAttrs },\n innerBlocks: raw.innerBlocks\n .filter((block) => block.blockName !== null || block.innerHTML.trim() !== '')\n .map(normaliseParsedBlock),\n originalContent: raw.innerHTML,\n };\n}\n\n/**\n * Extract content/text attributes from a block's innerHTML.\n * For core/paragraph: extract text between <p> tags -> attributes.content\n * For core/heading: extract text between <h1>-<h6> tags -> attributes.content\n * For core/list-item: extract text between <li> tags -> attributes.content\n * For core/image: extract src, alt from <img> tag -> attributes.url, attributes.alt\n * For core/button: extract text from <a> tag -> attributes.text\n */\nfunction extractAttributesFromHTML(\n blockName: string,\n innerHTML: string,\n attrs: Record<string, unknown>,\n): Record<string, unknown> {\n const extracted: Record<string, unknown> = {};\n\n switch (blockName) {\n case 'core/paragraph': {\n const match = innerHTML.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n break;\n }\n case 'core/heading': {\n const match = innerHTML.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n // Preserve the level from comment attrs if present\n if (attrs.level !== undefined) {\n extracted.level = attrs.level;\n }\n break;\n }\n case 'core/list-item': {\n const match = innerHTML.match(/<li[^>]*>([\\s\\S]*?)<\\/li>/);\n if (match) {\n extracted.content = match[1].trim();\n }\n break;\n }\n case 'core/image': {\n const imgMatch = innerHTML.match(/<img[^>]*>/);\n if (imgMatch) {\n const srcMatch = imgMatch[0].match(/src=\"([^\"]*)\"/);\n if (srcMatch) {\n extracted.url = srcMatch[1];\n }\n const altMatch = imgMatch[0].match(/alt=\"([^\"]*)\"/);\n if (altMatch) {\n extracted.alt = altMatch[1];\n }\n }\n break;\n }\n case 'core/button': {\n const match = innerHTML.match(/<a[^>]*>([\\s\\S]*?)<\\/a>/);\n if (match) {\n extracted.text = match[1].trim();\n }\n // Also extract the href as url\n const hrefMatch = innerHTML.match(/<a[^>]*href=\"([^\"]*)\"[^>]*>/);\n if (hrefMatch) {\n extracted.url = hrefMatch[1];\n }\n break;\n }\n }\n\n return extracted;\n}\n","/**\n * Block renderer: converts Block[] to Claude-friendly text representation.\n */\n\nimport type { Block } from '../yjs/types.js';\n\n/** Post metadata to display in the rendered output. */\nexport interface PostMetadata {\n status?: string;\n date?: string | null;\n slug?: string;\n sticky?: boolean;\n commentStatus?: string;\n excerpt?: string;\n}\n\n/**\n * Render a post's blocks as Claude-friendly text.\n *\n * Output format:\n * Title: \"Post Title Here\"\n * Status: draft\n *\n * [0] core/heading (level=2)\n * \"What Are Widgets?\"\n *\n * [1] core/paragraph\n * \"Widgets are fundamental building blocks...\"\n */\nexport function renderPost(title: string, blocks: Block[], metadata?: PostMetadata): string {\n const parts: string[] = [];\n parts.push(`Title: \"${title}\"`);\n\n if (metadata) {\n if (metadata.status) {\n parts.push(`Status: ${metadata.status}`);\n }\n if (metadata.date) {\n parts.push(`Date: ${metadata.date}`);\n }\n if (metadata.slug) {\n parts.push(`Slug: ${metadata.slug}`);\n }\n if (metadata.sticky) {\n parts.push('Sticky: yes');\n }\n if (metadata.commentStatus === 'closed') {\n parts.push('Comments: closed');\n }\n if (metadata.excerpt) {\n parts.push(`Excerpt: \"${metadata.excerpt}\"`);\n }\n }\n\n if (blocks.length > 0) {\n parts.push('');\n parts.push(renderBlockList(blocks));\n }\n\n return parts.join('\\n');\n}\n\n/**\n * Render a single block with its details.\n */\nexport function renderBlock(block: Block, index: string): string {\n const displayAttrs = getDisplayAttributes(block);\n const attrStr = Object.entries(displayAttrs)\n .map(([k, v]) => `${k}=${typeof v === 'string' ? `\"${v}\"` : v}`)\n .join(', ');\n\n const metadata = block.attributes.metadata as Record<string, unknown> | undefined;\n const hasNote = metadata?.noteId !== null && metadata?.noteId !== undefined;\n\n const header = attrStr\n ? `[${index}] ${block.name} (${attrStr})${hasNote ? ' [has note]' : ''}`\n : `[${index}] ${block.name}${hasNote ? ' [has note]' : ''}`;\n\n const lines: string[] = [header];\n\n const textContent = getBlockTextContent(block);\n if (textContent) {\n lines.push(` \"${textContent}\"`);\n }\n\n if (block.innerBlocks.length > 0) {\n const innerRendered = renderBlockList(block.innerBlocks, index, 1);\n lines.push(innerRendered);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render blocks as a list with indices.\n * @param blocks - The blocks to render\n * @param parentIndex - Parent index prefix for nested blocks (e.g., \"2\" -> \"2.0\", \"2.1\")\n * @param indent - Current indentation level\n */\nfunction renderBlockList(blocks: Block[], parentIndex?: string, indent: number = 0): string {\n const indentStr = ' '.repeat(indent);\n\n return blocks\n .map((block, i) => {\n const index = parentIndex !== undefined ? `${parentIndex}.${i}` : String(i);\n const rendered = renderBlock(block, index);\n // Indent each line of the rendered block\n if (indent > 0) {\n return rendered\n .split('\\n')\n .map((line) => indentStr + line)\n .join('\\n');\n }\n return rendered;\n })\n .join('\\n\\n');\n}\n\n/**\n * Get the primary text content of a block from its attributes.\n * Checks 'content' first, then 'text', then 'value', then 'citation'.\n */\nfunction getBlockTextContent(block: Block): string {\n for (const key of ['content', 'text', 'value', 'citation']) {\n const val = block.attributes[key];\n if (typeof val === 'string' && val.length > 0) {\n return val;\n }\n }\n return '';\n}\n\n/**\n * Get display-worthy attributes (non-content attributes that are useful to show).\n * For headings: show level\n * For images: show url, alt\n * For buttons: show url\n * For columns: show verticalAlignment\n * Skip 'content', 'text', 'value' (shown separately as text content)\n * Skip complex objects/arrays\n */\nfunction getDisplayAttributes(block: Block): Record<string, string | number | boolean> {\n const skipKeys = new Set(['content', 'text', 'value', 'citation', 'metadata']);\n const result: Record<string, string | number | boolean> = {};\n\n for (const [key, val] of Object.entries(block.attributes)) {\n if (skipKeys.has(key)) continue;\n if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {\n result[key] = val;\n }\n }\n\n return result;\n}\n","/**\n * Awareness protocol helpers for Claude's presence in collaborative editing.\n *\n * Builds the local awareness state identifying Claude as a collaborator\n * and parses the server's awareness state into a list of other collaborators.\n */\n\nimport type { CollaboratorInfo, AwarenessLocalState } from '../yjs/types.js';\nimport type { AwarenessState } from '../wordpress/types.js';\nimport type { WPUser } from '../wordpress/types.js';\n\n/**\n * Build the local awareness state that identifies Claude as a collaborator.\n * This state is sent with each sync request.\n */\nexport function buildAwarenessState(user: WPUser): AwarenessLocalState {\n return {\n collaboratorInfo: {\n id: user.id,\n name: `${user.name ?? user.slug} (Claude)`,\n slug: user.slug,\n avatar_urls: user.avatar_urls ?? {},\n browserType: 'Claude Code MCP',\n enteredAt: Date.now(),\n },\n // editorState with selection is required for Gutenberg to recognise us\n // as an active editor and process our CRDT updates in the live session.\n editorState: {\n selection: { type: 'none' },\n },\n };\n}\n\n/**\n * Parse the server's awareness state into a list of collaborators.\n * Excludes our own client ID and null (disconnected) states.\n */\nexport function parseCollaborators(\n awarenessState: AwarenessState,\n ownClientId: number,\n): CollaboratorInfo[] {\n const collaborators: CollaboratorInfo[] = [];\n\n for (const [clientIdStr, state] of Object.entries(awarenessState)) {\n const clientId = Number(clientIdStr);\n if (clientId === ownClientId) {\n continue;\n }\n if (state === null) {\n continue;\n }\n const info = (state as { collaboratorInfo?: CollaboratorInfo }).collaboratorInfo;\n if (info) {\n collaborators.push(info);\n }\n }\n\n return collaborators;\n}\n","/**\n * MIME type detection for WordPress media uploads.\n *\n * Maps file extensions to MIME types for the media types WordPress accepts.\n * Uses a static lookup table — no external dependencies.\n */\n\nimport { extname } from 'node:path';\n\n/** Media category derived from MIME type prefix. */\nexport type MediaCategory = 'image' | 'video' | 'audio' | 'application';\n\n/** Map of file extensions to MIME types for WordPress-supported media. */\nconst MIME_TYPES: Record<string, string> = {\n // Images\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n '.avif': 'image/avif',\n '.heic': 'image/heic',\n // Video\n '.mp4': 'video/mp4',\n '.m4v': 'video/mp4',\n '.mov': 'video/quicktime',\n '.avi': 'video/avi',\n '.wmv': 'video/x-ms-wmv',\n '.webm': 'video/webm',\n '.ogv': 'video/ogg',\n '.3gp': 'video/3gpp',\n // Audio\n '.mp3': 'audio/mpeg',\n '.ogg': 'audio/ogg',\n '.wav': 'audio/wav',\n '.flac': 'audio/flac',\n '.m4a': 'audio/mp4',\n '.aac': 'audio/aac',\n '.wma': 'audio/x-ms-wma',\n '.mid': 'audio/midi',\n '.midi': 'audio/midi',\n // Documents\n '.pdf': 'application/pdf',\n '.doc': 'application/msword',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.xls': 'application/vnd.ms-excel',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.odt': 'application/vnd.oasis.opendocument.text',\n '.ods': 'application/vnd.oasis.opendocument.spreadsheet',\n '.odp': 'application/vnd.oasis.opendocument.presentation',\n};\n\n/**\n * Get the MIME type for a file based on its extension.\n * Throws if the extension is not in the supported set.\n */\nexport function getMimeType(fileName: string): string {\n const ext = extname(fileName).toLowerCase();\n const mime = MIME_TYPES[ext];\n if (!mime) {\n throw new Error(\n `Unsupported file type: ${ext || '(no extension)'}. ` +\n `Supported types: ${Object.keys(MIME_TYPES).join(', ')}`,\n );\n }\n return mime;\n}\n\n/**\n * Derive the media category from a MIME type string.\n * Returns 'image', 'video', 'audio', or 'application'.\n */\nexport function getMediaCategory(mimeType: string): MediaCategory {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType.startsWith('video/')) return 'video';\n if (mimeType.startsWith('audio/')) return 'audio';\n return 'application';\n}\n","/**\n * Session manager: orchestrates the full connection lifecycle for\n * collaborative editing of WordPress posts via the Gutenberg sync protocol.\n *\n * Lifecycle: connect → openPost → edit/read → closePost → disconnect\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\nimport * as Y from 'yjs';\nimport { DocumentManager } from '../yjs/document-manager.js';\nimport { WordPressApiClient, WordPressApiError } from '../wordpress/api-client.js';\nimport { SyncClient } from '../wordpress/sync-client.js';\nimport {\n createSyncStep1,\n processIncomingUpdate,\n createCompactionUpdate,\n createUpdateFromChange,\n} from '../yjs/sync-protocol.js';\nimport { computeTextDelta, findHtmlSafeChunkEnd } from '../yjs/block-converter.js';\nimport { parseBlocks, parsedBlockToBlock } from '../blocks/parser.js';\nimport { renderPost, renderBlock, type PostMetadata } from '../blocks/renderer.js';\nimport { buildAwarenessState, parseCollaborators } from './awareness.js';\nimport { DEFAULT_SYNC_CONFIG } from '../wordpress/types.js';\nimport {\n CRDT_DOC_VERSION,\n CRDT_STATE_MAP_KEY,\n CRDT_STATE_MAP_SAVED_AT_KEY,\n CRDT_STATE_MAP_SAVED_BY_KEY,\n CRDT_STATE_MAP_VERSION_KEY,\n} from '../yjs/types.js';\nimport type { Block, CollaboratorInfo, AwarenessLocalState } from '../yjs/types.js';\nimport { BlockTypeRegistry } from '../yjs/block-type-registry.js';\nimport { getMimeType } from '../wordpress/mime-types.js';\nimport type {\n WordPressConfig,\n WPMediaItem,\n WPNote,\n WPTerm,\n WPUser,\n WPPost,\n} from '../wordpress/types.js';\n\nexport type SessionState = 'disconnected' | 'connected' | 'editing';\n\n/**\n * Origin marker for local edits made through the session manager.\n * Used to distinguish local changes from sync updates when observing Y.Doc events.\n */\nconst LOCAL_ORIGIN = 'local';\n\n/** Streaming chunk size range in characters. Randomized for a natural feel. */\nconst STREAM_CHUNK_SIZE_MIN = 2;\nconst STREAM_CHUNK_SIZE_MAX = 6;\n\n/** Delay between streaming chunks in milliseconds. */\nconst STREAM_CHUNK_DELAY_MS = 100;\n\n/** Minimum text length to trigger streaming (short text is applied atomically). */\nconst STREAM_THRESHOLD = 20;\n\n/** Input shape for blocks with optional recursive inner blocks. */\nexport interface BlockInput {\n name: string;\n content?: string;\n attributes?: Record<string, unknown>;\n innerBlocks?: BlockInput[];\n}\n\n/** A streaming target: a specific attribute in a block that needs progressive insertion. */\ninterface StreamTarget {\n blockIndex: string;\n attrName: string;\n value: string;\n}\n\n/** Result of a single find-and-replace edit operation. */\nexport interface TextEditResult {\n find: string;\n replace: string;\n applied: boolean;\n /** Error message if the edit was not applied. */\n error?: string;\n}\n\n/** Result of editBlockText(). */\nexport interface EditBlockTextResult {\n edits: TextEditResult[];\n appliedCount: number;\n failedCount: number;\n /** The updated text content of the attribute after all edits. */\n updatedText: string;\n}\n\n/**\n * Find the Nth occurrence (1-indexed) of `search` within `text`.\n * Returns the character index, or -1 if fewer than N occurrences exist.\n */\nfunction findNthOccurrence(text: string, search: string, n: number): number {\n let pos = -1;\n for (let i = 0; i < n; i++) {\n pos = text.indexOf(search, pos + 1);\n if (pos === -1) return -1;\n }\n return pos;\n}\n\n/**\n * Recursively prepare a block tree for insertion.\n * Applies default attributes, sets isValid/clientId, and separates\n * streamable rich-text content from atomic structure.\n *\n * @returns The Block (with empty placeholders for streamable content)\n * and a flat list of StreamTargets for progressive insertion.\n */\nfunction prepareBlockTree(\n input: BlockInput,\n indexPrefix: string,\n registry: BlockTypeRegistry,\n parentName?: string,\n): { block: Block; streamTargets: StreamTarget[] } {\n // When using the API-sourced registry, validate block type existence.\n // Skip all validation for the fallback registry — it only knows a subset.\n if (!registry.isUsingFallback()) {\n if (!registry.isKnownBlockType(input.name)) {\n throw new Error(\n `Unknown block type: ${input.name}. This block type is not registered on the WordPress site.`,\n );\n }\n\n // Auto-wrap content into inner core/paragraph for blocks that use InnerBlocks\n // for their primary content. The `supports.allowedBlocks` API flag (exposed as\n // supportsInnerBlocks) is the canonical signal — e.g., core/quote has it (inner\n // paragraphs), while core/pullquote doesn't (uses `value` directly).\n if (input.content !== undefined && !registry.hasAttribute(input.name, 'content')) {\n const usesInnerBlocks = registry.supportsInnerBlocks(input.name);\n const allowedBlocks = registry.getAllowedBlocks(input.name);\n const paragraphAllowed =\n usesInnerBlocks &&\n (allowedBlocks === null || allowedBlocks.includes('core/paragraph')) &&\n registry.isKnownBlockType('core/paragraph');\n\n if (paragraphAllowed) {\n const wrappedContent = input.content;\n const existingInnerBlocks = input.innerBlocks;\n input = {\n ...input,\n content: undefined,\n innerBlocks: [\n { name: 'core/paragraph', content: wrappedContent },\n ...(existingInnerBlocks ?? []),\n ],\n };\n } else {\n const info = registry.getBlockTypeInfo(input.name);\n const richTextAttrs = info?.attributes.filter((a) => a.richText).map((a) => a.name) ?? [];\n const richTextHint =\n richTextAttrs.length > 0\n ? ` This block's rich-text attributes are: ${richTextAttrs.join(', ')}. Pass text via the \"attributes\" parameter instead.`\n : '';\n const innerBlocksHint = usesInnerBlocks\n ? ' Alternatively, pass content via the \"innerBlocks\" parameter.'\n : '';\n throw new Error(\n `Block type ${input.name} does not have a \"content\" attribute.${richTextHint}${innerBlocksHint}`,\n );\n }\n }\n\n // Validate provided attributes exist in the block schema\n if (input.attributes) {\n const knownAttrs = registry.getAttributeNames(input.name);\n if (knownAttrs) {\n const unknownAttrs = Object.keys(input.attributes).filter((k) => !knownAttrs.has(k));\n if (unknownAttrs.length > 0) {\n throw new Error(\n `Unknown attribute${unknownAttrs.length > 1 ? 's' : ''} for ${input.name}: ${unknownAttrs.join(', ')}. ` +\n `Known attributes: ${[...knownAttrs].sort().join(', ')}`,\n );\n }\n }\n }\n\n // Validate parent constraint\n const parentConstraint = registry.getParent(input.name);\n if (parentConstraint) {\n if (!parentName) {\n throw new Error(\n `Block type ${input.name} cannot be inserted at the top level. It must be nested inside: ${parentConstraint.join(', ')}`,\n );\n }\n if (!parentConstraint.includes(parentName)) {\n throw new Error(\n `Block type ${input.name} can only be nested inside: ${parentConstraint.join(', ')} (got ${parentName})`,\n );\n }\n }\n }\n\n const defaults = registry.getDefaultAttributes(input.name);\n const attrs = { ...defaults, ...input.attributes };\n const streamTargets: StreamTarget[] = [];\n\n // Handle 'content' field\n if (input.content !== undefined) {\n if (\n registry.isRichTextAttribute(input.name, 'content') &&\n input.content.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ blockIndex: indexPrefix, attrName: 'content', value: input.content });\n attrs.content = '';\n } else {\n attrs.content = input.content;\n }\n }\n\n // Check other attributes for streaming\n for (const [key, value] of Object.entries(attrs)) {\n if (\n key !== 'content' &&\n registry.isRichTextAttribute(input.name, key) &&\n typeof value === 'string' &&\n value.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ blockIndex: indexPrefix, attrName: key, value });\n attrs[key] = '';\n }\n }\n\n // Recurse into inner blocks with parent/allowedBlocks validation\n const innerBlocks: Block[] = [];\n if (input.innerBlocks) {\n // Validate parent's allowedBlocks constraint\n if (!registry.isUsingFallback()) {\n const allowedBlocks = registry.getAllowedBlocks(input.name);\n if (allowedBlocks) {\n for (const inner of input.innerBlocks) {\n if (!allowedBlocks.includes(inner.name)) {\n throw new Error(\n `Block type ${input.name} only allows these inner blocks: ${allowedBlocks.join(', ')} (got ${inner.name})`,\n );\n }\n }\n }\n }\n\n for (let i = 0; i < input.innerBlocks.length; i++) {\n const childIndex = `${indexPrefix}.${i}`;\n const prepared = prepareBlockTree(input.innerBlocks[i], childIndex, registry, input.name);\n innerBlocks.push(prepared.block);\n streamTargets.push(...prepared.streamTargets);\n }\n }\n\n const block: Block = {\n name: input.name,\n clientId: crypto.randomUUID(),\n attributes: attrs,\n innerBlocks,\n isValid: true,\n };\n\n return { block, streamTargets };\n}\n\nexport class SessionManager {\n private _apiClient: WordPressApiClient | null = null;\n private _syncClient: SyncClient | null = null;\n private documentManager: DocumentManager;\n private registry: BlockTypeRegistry;\n private _doc: Y.Doc | null = null;\n private _user: WPUser | null = null;\n private _currentPost: WPPost | null = null;\n private state: SessionState = 'disconnected';\n private awarenessState: AwarenessLocalState | null = null;\n private collaborators: CollaboratorInfo[] = [];\n private notesSupported = false;\n private updateHandler: ((update: Uint8Array, origin: unknown) => void) | null = null;\n private commentDoc: Y.Doc | null = null;\n private commentUpdateHandler: ((update: Uint8Array, origin: unknown) => void) | null = null;\n\n /** True when the post has been deleted or trashed externally. */\n private postGone = false;\n /** Human-readable reason for why the post is gone. */\n private postGoneReason: string | null = null;\n /** In-flight post-existence check promise, used as a lock. */\n private postGoneCheck: Promise<void> | null = null;\n /** Timer for periodic post health checks (detects trashing via REST API). */\n private postHealthCheckTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Background streaming queue — closures that call streamTargets/streamTextToYText. */\n private streamQueue: Array<() => Promise<void>> = [];\n /** Promise for the currently running queue processor, or null if idle. */\n private streamProcessor: Promise<void> | null = null;\n\n /** Room name for the comment sync room. */\n private static readonly COMMENT_ROOM = 'root/comment';\n\n /**\n * Max time (ms) to wait for sync to populate the doc before loading from REST API.\n * Must be long enough for the step1/step2 handshake round-trip:\n * Gutenberg 22.8+ polls at 4s solo / 1s with collaborators, so the handshake\n * can take up to ~8s (step1 waits for browser poll, step2 waits for MCP poll).\n * Set to 0 in tests to skip sync wait.\n */\n syncWaitTimeout = 15_000;\n\n /**\n * Interval (ms) for periodic post health checks via REST API.\n * Detects trashing (which bypasses the Y.Doc) even when sync keeps working.\n * Set to 0 in tests to disable.\n */\n postHealthCheckInterval = 30_000;\n\n // --- Throwing getters for state-dependent fields ---\n\n private get apiClient(): WordPressApiClient {\n if (!this._apiClient) throw new Error('No API client (not connected)');\n return this._apiClient;\n }\n\n private get user(): WPUser {\n if (!this._user) throw new Error('No user (not connected)');\n return this._user;\n }\n\n private get doc(): Y.Doc {\n if (!this._doc) throw new Error('No Y.Doc (no post open)');\n return this._doc;\n }\n\n private get syncClient(): SyncClient {\n if (!this._syncClient) throw new Error('No sync client (no post open)');\n return this._syncClient;\n }\n\n private get currentPost(): WPPost {\n if (!this._currentPost) throw new Error('No current post (no post open)');\n return this._currentPost;\n }\n\n constructor() {\n this.registry = BlockTypeRegistry.createFallback();\n this.documentManager = new DocumentManager(this.registry);\n }\n\n // --- Connection ---\n\n /**\n * Connect to a WordPress site.\n * Validates credentials and sync endpoint availability.\n */\n async connect(config: WordPressConfig): Promise<WPUser> {\n if (this.state === 'editing') {\n throw new Error('Cannot connect while a post is open. Call closePost() first.');\n }\n if (this.state === 'connected') {\n await this.disconnect();\n }\n\n this._apiClient = new WordPressApiClient(config);\n\n // Validate credentials\n const user = await this.apiClient.validateConnection();\n this._user = user;\n\n // Validate sync endpoint is available (the real gate for collaborative editing)\n await this.apiClient.validateSyncEndpoint();\n\n // Fetch block type registry from the API; fall back to hardcoded if unavailable\n try {\n const blockTypes = await this.apiClient.getBlockTypes();\n this.registry = BlockTypeRegistry.fromApiResponse(blockTypes);\n } catch {\n this.registry = BlockTypeRegistry.createFallback();\n }\n this.documentManager.setRegistry(this.registry);\n\n // Check if the site supports notes (block comments)\n try {\n this.notesSupported = await this.apiClient.checkNotesSupport();\n } catch {\n this.notesSupported = false;\n }\n\n // Build awareness state from user info\n this.awarenessState = buildAwarenessState(user);\n\n this.state = 'connected';\n return user;\n }\n\n /**\n * Disconnect from the WordPress site.\n */\n async disconnect(): Promise<void> {\n if (this.state === 'editing') {\n await this.closePost();\n }\n\n this._apiClient = null;\n this._user = null;\n this.awarenessState = null;\n this.collaborators = [];\n this.notesSupported = false;\n this.state = 'disconnected';\n }\n\n // --- Posts ---\n\n /**\n * List posts (delegates to API client).\n */\n async listPosts(options?: {\n status?: string;\n search?: string;\n perPage?: number;\n }): Promise<WPPost[]> {\n this.requireState('connected', 'editing');\n return this.apiClient.listPosts(options);\n }\n\n /**\n * Open a post for collaborative editing.\n * Creates Y.Doc, loads initial content, starts sync.\n */\n async openPost(postId: number): Promise<void> {\n this.requireState('connected');\n\n // Fetch post from API\n const post = await this.apiClient.getPost(postId);\n this._currentPost = post;\n\n // Create an EMPTY Y.Doc — don't load content yet.\n // We first sync with the server to receive any existing CRDT state.\n // Loading content independently would create divergent CRDT histories,\n // causing duplicate blocks when two clients sync.\n const doc = this.documentManager.createDoc();\n this._doc = doc;\n\n // Create sync client\n const syncClient = new SyncClient(this.apiClient, { ...DEFAULT_SYNC_CONFIG });\n this._syncClient = syncClient;\n\n // Start sync with room = postType/${post.type}:${postId}\n const room = `postType/${post.type}:${postId}`;\n const initialUpdates = [createSyncStep1(doc)];\n\n syncClient.start(room, doc.clientID, initialUpdates, {\n onUpdate: (update) => {\n try {\n return processIncomingUpdate(doc, update);\n } catch {\n return null;\n }\n },\n onAwareness: (awarenessState) => {\n this.collaborators = parseCollaborators(awarenessState, doc.clientID);\n },\n onStatusChange: (_status, error) => {\n if (\n _status === 'error' &&\n error instanceof WordPressApiError &&\n (error.status === 403 || error.status === 404 || error.status === 410)\n ) {\n this.checkPostStillExists();\n }\n },\n onCompactionRequested: () => {\n return createCompactionUpdate(doc);\n },\n getAwarenessState: () => {\n return this.awarenessState;\n },\n });\n\n // Wait for the sync handshake to populate the doc with remote content.\n // The handshake takes multiple poll cycles:\n // Poll 1: We send sync_step1 → receive peer's sync_step1\n // Poll 2: We send sync_step2 → receive peer's sync_step2 (their full state)\n // So we wait until the doc has blocks (meaning remote state arrived),\n // or timeout (meaning no peers are editing this post).\n if (this.syncWaitTimeout > 0) {\n await new Promise<void>((resolve) => {\n let resolved = false;\n const done = () => {\n if (!resolved) {\n resolved = true;\n doc.off('updateV2', onDocUpdate);\n resolve();\n }\n };\n\n const timeout = setTimeout(done, this.syncWaitTimeout);\n\n const onDocUpdate = () => {\n const blocks = this.documentManager.getBlocks(doc);\n const title = this.documentManager.getTitle(doc);\n if (blocks.length > 0 || title.length > 0) {\n clearTimeout(timeout);\n done();\n }\n };\n\n doc.on('updateV2', onDocUpdate);\n });\n }\n\n // If the doc is still empty after sync, load content from the REST API.\n // This means we're the first CRDT client for this post.\n const existingBlocks = this.documentManager.getBlocks(doc);\n if (existingBlocks.length === 0) {\n doc.transact(() => {\n // Set title\n if (post.title.raw) {\n this.documentManager.setTitle(doc, post.title.raw);\n }\n\n // Parse content into blocks\n if (post.content.raw) {\n const parsedBlocks = parseBlocks(post.content.raw);\n const blocks = parsedBlocks.map(parsedBlockToBlock);\n this.documentManager.setBlocks(doc, blocks);\n this.documentManager.setContent(doc, post.content.raw);\n }\n\n // Set excerpt\n if (post.excerpt.raw) {\n this.documentManager.setProperty(doc, 'excerpt', post.excerpt.raw);\n }\n\n // Set other post properties\n this.documentManager.setProperty(doc, 'status', post.status);\n this.documentManager.setProperty(doc, 'slug', post.slug);\n this.documentManager.setProperty(doc, 'author', post.author);\n\n // Set additional synced post properties\n if (post.categories) {\n this.documentManager.setProperty(doc, 'categories', post.categories);\n }\n if (post.tags) {\n this.documentManager.setProperty(doc, 'tags', post.tags);\n }\n if (post.featured_media !== undefined) {\n this.documentManager.setProperty(doc, 'featured_media', post.featured_media);\n }\n if (post.comment_status) {\n this.documentManager.setProperty(doc, 'comment_status', post.comment_status);\n }\n if (post.sticky !== undefined) {\n this.documentManager.setProperty(doc, 'sticky', post.sticky);\n }\n if (post.date) {\n this.documentManager.setProperty(doc, 'date', post.date);\n }\n }, LOCAL_ORIGIN);\n }\n\n // Set up Y.Doc observer to queue updates for local changes\n this.updateHandler = (update: Uint8Array, origin: unknown) => {\n // Only queue updates from local edits, not from sync\n if (origin === LOCAL_ORIGIN) {\n const syncUpdate = createUpdateFromChange(update);\n syncClient.queueUpdate(room, syncUpdate);\n }\n };\n doc.on('updateV2', this.updateHandler);\n\n // Join the root/comment room for real-time note sync.\n // This room's state map acts as a change signal: when savedAt/savedBy\n // are updated, other clients re-fetch notes from the REST API.\n if (this.notesSupported) {\n const commentDoc = new Y.Doc();\n this.commentDoc = commentDoc;\n\n // Initialise the state map (same pattern as the post doc)\n commentDoc.transact(() => {\n const stateMap = commentDoc.getMap(CRDT_STATE_MAP_KEY);\n stateMap.set(CRDT_STATE_MAP_VERSION_KEY, CRDT_DOC_VERSION);\n });\n\n this.commentUpdateHandler = (update: Uint8Array, origin: unknown) => {\n if (origin === LOCAL_ORIGIN) {\n const syncUpdate = createUpdateFromChange(update);\n syncClient.queueUpdate(SessionManager.COMMENT_ROOM, syncUpdate);\n }\n };\n commentDoc.on('updateV2', this.commentUpdateHandler);\n\n syncClient.addRoom(\n SessionManager.COMMENT_ROOM,\n commentDoc.clientID,\n [createSyncStep1(commentDoc)],\n {\n onUpdate: (update) => {\n try {\n return processIncomingUpdate(commentDoc, update);\n } catch {\n return null;\n }\n },\n onAwareness: () => {},\n onCompactionRequested: () => createCompactionUpdate(commentDoc),\n getAwarenessState: () => null,\n },\n );\n }\n\n // Periodic health check via REST API to detect trashing.\n // Trashing bypasses the Y.Doc (it's a direct DB status change),\n // so we poll getPost() to catch it.\n if (this.postHealthCheckInterval > 0) {\n this.postHealthCheckTimer = setInterval(() => {\n this.checkPostStillExists();\n }, this.postHealthCheckInterval);\n }\n\n this.state = 'editing';\n }\n\n /**\n * Create a new post and open it for editing.\n */\n async createPost(data: { title?: string; content?: string }): Promise<WPPost> {\n this.requireState('connected');\n\n const post = await this.apiClient.createPost({\n title: data.title,\n content: data.content,\n status: 'draft',\n });\n\n await this.openPost(post.id);\n\n return post;\n }\n\n /**\n * Close the currently open post (stop sync).\n * Drains the streaming queue first to ensure all content is delivered.\n */\n async closePost(): Promise<void> {\n this.requireState('editing');\n await this.drainStreamQueue();\n\n if (this._syncClient) {\n this._syncClient.stop();\n this._syncClient = null;\n }\n\n if (this._doc && this.updateHandler) {\n this._doc.off('updateV2', this.updateHandler);\n this.updateHandler = null;\n }\n\n if (this.commentDoc && this.commentUpdateHandler) {\n this.commentDoc.off('updateV2', this.commentUpdateHandler);\n this.commentUpdateHandler = null;\n }\n\n if (this.postHealthCheckTimer !== null) {\n clearInterval(this.postHealthCheckTimer);\n this.postHealthCheckTimer = null;\n }\n\n // Wait for any in-flight post-existence check to complete before\n // clearing state, so it doesn't mutate a subsequent session.\n if (this.postGoneCheck) {\n await this.postGoneCheck;\n }\n\n this._doc = null;\n this.commentDoc = null;\n this._currentPost = null;\n this.collaborators = [];\n this.postGone = false;\n this.postGoneReason = null;\n this.postGoneCheck = null;\n this.state = 'connected';\n }\n\n // --- Reading ---\n\n /**\n * Render the current post as Claude-friendly text, including metadata.\n */\n readPost(): string {\n this.requireEditablePost();\n\n const title = this.documentManager.getTitle(this.doc);\n const blocks = this.documentManager.getBlocks(this.doc);\n\n // Gather metadata from Y.Doc (preferred, reflects collaborative state) and currentPost (fallback)\n const metadata: PostMetadata = {\n status:\n (this.documentManager.getProperty(this.doc, 'status') as string | undefined) ??\n this._currentPost?.status,\n date:\n (this.documentManager.getProperty(this.doc, 'date') as string | undefined) ??\n this._currentPost?.date ??\n undefined,\n slug:\n (this.documentManager.getProperty(this.doc, 'slug') as string | undefined) ??\n this._currentPost?.slug,\n sticky:\n (this.documentManager.getProperty(this.doc, 'sticky') as boolean | undefined) ??\n this._currentPost?.sticky,\n commentStatus:\n (this.documentManager.getProperty(this.doc, 'comment_status') as string | undefined) ??\n this._currentPost?.comment_status,\n excerpt:\n (this.documentManager.getProperty(this.doc, 'excerpt') as string | undefined) || undefined,\n };\n\n return renderPost(title, blocks, metadata);\n }\n\n /**\n * Read a specific block by index (dot notation).\n */\n readBlock(index: string): string {\n this.requireEditablePost();\n\n const block = this.documentManager.getBlockByIndex(this.doc, index);\n if (!block) {\n throw new Error(`Block not found at index ${index}`);\n }\n return renderBlock(block, index);\n }\n\n // --- Editing ---\n\n /**\n * Update a block's content and/or attributes.\n *\n * Rich-text attributes that exceed the streaming threshold are streamed\n * in chunks so the browser sees progressive updates (like fast typing).\n * Non-rich-text and short changes are applied atomically.\n */\n updateBlock(\n index: string,\n changes: { content?: string; attributes?: Record<string, unknown> },\n ): void {\n this.requireEditablePost();\n\n // Set cursor position BEFORE the edit — pointing to existing items\n // the browser already has. Gutenberg requires a real cursor position\n // to process remote edits, but if we set it AFTER the edit, the cursor\n // references new items the browser doesn't have yet (causing a crash).\n this.updateCursorPosition(index);\n\n // Identify which changes should be streamed vs applied atomically.\n // Look up the block name to determine rich-text attributes.\n const block = this.documentManager.getBlockByIndex(this.doc, index);\n if (!block) return;\n\n const streamTargets: Array<{ attrName: string; newValue: string }> = [];\n const atomicChanges: { content?: string; attributes?: Record<string, unknown> } = {};\n\n // Check 'content' field\n if (changes.content !== undefined) {\n if (\n this.registry.isRichTextAttribute(block.name, 'content') &&\n changes.content.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ attrName: 'content', newValue: changes.content });\n } else {\n atomicChanges.content = changes.content;\n }\n }\n\n // Check explicit attributes\n if (changes.attributes) {\n const atomicAttrs: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(changes.attributes)) {\n if (\n this.registry.isRichTextAttribute(block.name, key) &&\n typeof value === 'string' &&\n value.length >= STREAM_THRESHOLD\n ) {\n streamTargets.push({ attrName: key, newValue: value });\n } else {\n atomicAttrs[key] = value;\n }\n }\n if (Object.keys(atomicAttrs).length > 0) {\n atomicChanges.attributes = atomicAttrs;\n }\n }\n\n // Apply atomic changes (non-streaming) in one transaction\n if (atomicChanges.content !== undefined || atomicChanges.attributes) {\n this.doc.transact(() => {\n this.documentManager.updateBlock(this.doc, index, atomicChanges);\n }, LOCAL_ORIGIN);\n }\n\n // Push atomic changes to browser immediately\n this.syncClient.flushQueue();\n\n // Queue rich-text attributes for background streaming\n const queueTargets: StreamTarget[] = streamTargets.map((t) => ({\n blockIndex: index,\n attrName: t.attrName,\n value: t.newValue,\n }));\n this.enqueueStreamTargets(queueTargets);\n }\n\n /**\n * Apply surgical find-and-replace edits to a block's rich-text attribute.\n *\n * Each edit is applied as an atomic Y.Text delta (retain + delete + insert).\n * The Y.Text is re-read before each edit to get correct positions after\n * previous edits and any concurrent remote changes.\n *\n * @param index Block index (e.g., \"0\", \"2.1\")\n * @param edits Array of find/replace operations applied sequentially\n * @param attribute Rich-text attribute name (default: \"content\")\n * @returns Structured result with per-edit success/failure and updated text\n */\n editBlockText(\n index: string,\n edits: Array<{ find: string; replace: string; occurrence?: number }>,\n attribute?: string,\n ): EditBlockTextResult {\n this.requireEditablePost();\n\n const attrName = attribute ?? 'content';\n\n const block = this.documentManager.getBlockByIndex(this.doc, index);\n if (!block) {\n throw new Error(`Block ${index} not found.`);\n }\n\n if (!this.registry.isRichTextAttribute(block.name, attrName)) {\n const richTextAttrs = this.registry.getRichTextAttributes(block.name).join(', ');\n const hint = richTextAttrs\n ? ` Rich-text attributes for ${block.name}: ${richTextAttrs}.`\n : ` ${block.name} has no rich-text attributes.`;\n throw new Error(\n `Attribute \"${attrName}\" on ${block.name} is not a rich-text attribute. Use wp_update_block to change non-text attributes.${hint}`,\n );\n }\n\n const ytext = this.documentManager.getBlockAttributeYText(this.doc, index, attrName);\n if (!ytext) {\n throw new Error(\n `Attribute \"${attrName}\" is empty on block ${index}. Use wp_update_block to set initial content.`,\n );\n }\n\n // Set cursor to the block being edited for collaborative awareness display.\n // This targets the block's content Y.Text (regardless of which attribute we're\n // actually editing) because that's what Gutenberg uses for cursor positioning.\n // For blocks without a content attribute, this is a no-op — harmless.\n this.updateCursorPosition(index);\n\n const results: TextEditResult[] = [];\n let appliedCount = 0;\n\n for (const edit of edits) {\n if (edit.find === '') {\n results.push({\n find: edit.find,\n replace: edit.replace,\n applied: false,\n error: 'Empty find string is not allowed.',\n });\n continue;\n }\n\n // Validate occurrence before searching\n const occurrence = edit.occurrence ?? 1;\n if (!Number.isInteger(occurrence) || occurrence < 1) {\n results.push({\n find: edit.find,\n replace: edit.replace,\n applied: false,\n error: `Invalid occurrence value: ${occurrence}. Must be a positive integer (>= 1).`,\n });\n continue;\n }\n\n // Re-read current text for each edit (previous edits shift positions)\n const currentText = ytext.toJSON();\n const pos = findNthOccurrence(currentText, edit.find, occurrence);\n\n if (pos === -1) {\n const reason =\n occurrence > 1\n ? `Occurrence ${occurrence} of \"${edit.find}\" not found in current content.`\n : `\"${edit.find}\" not found in current content.`;\n results.push({\n find: edit.find,\n replace: edit.replace,\n applied: false,\n error: reason,\n });\n continue;\n }\n\n // Apply as a single atomic delta: retain + delete + insert\n this.doc.transact(() => {\n const ops: Array<{ retain?: number; delete?: number; insert?: string }> = [];\n if (pos > 0) ops.push({ retain: pos });\n if (edit.find.length > 0) ops.push({ delete: edit.find.length });\n if (edit.replace.length > 0) ops.push({ insert: edit.replace });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n\n results.push({ find: edit.find, replace: edit.replace, applied: true });\n appliedCount++;\n }\n\n // Flush once after all edits for prompt sync to browser\n if (appliedCount > 0) {\n this.syncClient.flushQueue();\n }\n\n return {\n edits: results,\n appliedCount,\n failedCount: results.length - appliedCount,\n updatedText: ytext.toJSON(),\n };\n }\n\n /**\n * Insert a new block at position.\n *\n * The block structure (with empty content) is inserted atomically,\n * then rich-text content is streamed in progressively.\n * Supports recursive inner blocks.\n */\n insertBlock(position: number, block: BlockInput): void {\n this.requireEditablePost();\n\n const blockIndex = String(position);\n const { block: fullBlock, streamTargets } = prepareBlockTree(block, blockIndex, this.registry);\n\n // Insert block structure atomically and push to browser immediately\n this.doc.transact(() => {\n this.documentManager.insertBlock(this.doc, position, fullBlock);\n }, LOCAL_ORIGIN);\n this.syncClient.flushQueue();\n\n // Queue rich-text content for background streaming\n this.enqueueStreamTargets(streamTargets);\n }\n\n /**\n * Remove blocks starting at index.\n */\n removeBlocks(startIndex: number, count: number): void {\n this.requireEditablePost();\n this.doc.transact(() => {\n this.documentManager.removeBlocks(this.doc, startIndex, count);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Move a block from one position to another.\n */\n moveBlock(fromIndex: number, toIndex: number): void {\n this.requireEditablePost();\n this.doc.transact(() => {\n this.documentManager.moveBlock(this.doc, fromIndex, toIndex);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Replace a range of blocks with new ones.\n *\n * Old blocks are removed and new block structures (with empty content)\n * are inserted atomically. Rich-text content is then streamed progressively.\n */\n replaceBlocks(startIndex: number, count: number, newBlocks: BlockInput[]): void {\n this.requireEditablePost();\n\n // Prepare all blocks recursively\n const allStreamTargets: StreamTarget[] = [];\n const fullBlocks: Block[] = newBlocks.map((b, i) => {\n const blockIndex = String(startIndex + i);\n const { block, streamTargets } = prepareBlockTree(b, blockIndex, this.registry);\n allStreamTargets.push(...streamTargets);\n return block;\n });\n\n // Remove old blocks and insert new structures atomically\n this.doc.transact(() => {\n this.documentManager.removeBlocks(this.doc, startIndex, count);\n for (let i = 0; i < fullBlocks.length; i++) {\n this.documentManager.insertBlock(this.doc, startIndex + i, fullBlocks[i]);\n }\n }, LOCAL_ORIGIN);\n\n // Push block structures to browser immediately\n this.syncClient.flushQueue();\n\n // Queue rich-text content for background streaming\n this.enqueueStreamTargets(allStreamTargets);\n }\n\n /**\n * Insert a block as an inner block of an existing block.\n */\n insertInnerBlock(parentIndex: string, position: number, block: BlockInput): void {\n this.requireEditablePost();\n\n const blockIndex = `${parentIndex}.${position}`;\n const { block: fullBlock, streamTargets } = prepareBlockTree(block, blockIndex, this.registry);\n\n this.doc.transact(() => {\n this.documentManager.insertInnerBlock(this.doc, parentIndex, position, fullBlock);\n }, LOCAL_ORIGIN);\n this.syncClient.flushQueue();\n\n this.enqueueStreamTargets(streamTargets);\n }\n\n /**\n * Remove inner blocks from an existing block.\n */\n removeInnerBlocks(parentIndex: string, startIndex: number, count: number): void {\n this.requireEditablePost();\n this.doc.transact(() => {\n this.documentManager.removeInnerBlocks(this.doc, parentIndex, startIndex, count);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Set the post title.\n *\n * Long titles are streamed progressively; short titles are applied atomically.\n */\n setTitle(title: string): void {\n this.requireEditablePost();\n\n if (title.length < STREAM_THRESHOLD) {\n this.doc.transact(() => {\n this.documentManager.setTitle(this.doc, title);\n }, LOCAL_ORIGIN);\n this.syncClient.flushQueue();\n return;\n }\n\n // Get the title Y.Text\n const documentMap = this.documentManager.getDocumentMap(this.doc);\n let ytext = documentMap.get('title');\n if (!(ytext instanceof Y.Text)) {\n // Create Y.Text if it doesn't exist\n this.doc.transact(() => {\n const newYText = new Y.Text();\n documentMap.set('title', newYText);\n }, LOCAL_ORIGIN);\n ytext = documentMap.get('title');\n }\n if (ytext instanceof Y.Text) {\n const titleYText = ytext;\n this.syncClient.flushQueue();\n this.enqueueStreaming(() => this.streamTextToYText(titleYText, title));\n }\n }\n\n /**\n * Trigger a save. Drains the streaming queue first to ensure\n * all content is committed before marking saved.\n */\n async save(): Promise<void> {\n this.requireEditablePost();\n await this.drainStreamQueue();\n this.doc.transact(() => {\n this.documentManager.markSaved(this.doc);\n }, LOCAL_ORIGIN);\n }\n\n // --- Post Metadata ---\n\n /**\n * List categories, optionally filtered by search term.\n */\n async listCategories(options?: { search?: string; perPage?: number }): Promise<WPTerm[]> {\n this.requireState('connected', 'editing');\n return this.apiClient.listTerms('categories', options);\n }\n\n /**\n * List tags, optionally filtered by search term.\n */\n async listTags(options?: { search?: string; perPage?: number }): Promise<WPTerm[]> {\n this.requireState('connected', 'editing');\n return this.apiClient.listTerms('tags', options);\n }\n\n /**\n * Set the post publication status.\n * Updates both the Y.Doc (for collaborative sync) and the REST API (for persistence).\n */\n async setPostStatus(status: string): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ status });\n }\n\n /**\n * Set the post excerpt.\n * Updates both the Y.Doc and the REST API.\n */\n async setExcerpt(excerpt: string): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ excerpt });\n }\n\n /**\n * Set the post categories by name.\n * Resolves names to IDs (creating categories that don't exist), then updates\n * both the Y.Doc and the REST API.\n */\n async setCategories(\n names: string[],\n ): Promise<{ post: WPPost; resolved: Array<{ name: string; id: number; created: boolean }> }> {\n this.requireEditablePost();\n const resolved = await this.resolveTerms('categories', names);\n const ids = resolved.map((r) => r.id);\n\n const post = await this.updatePostMeta({ categories: ids });\n return { post, resolved };\n }\n\n /**\n * Set the post tags by name.\n * Resolves names to IDs (creating tags that don't exist), then updates\n * both the Y.Doc and the REST API.\n */\n async setTags(\n names: string[],\n ): Promise<{ post: WPPost; resolved: Array<{ name: string; id: number; created: boolean }> }> {\n this.requireEditablePost();\n const resolved = await this.resolveTerms('tags', names);\n const ids = resolved.map((r) => r.id);\n\n const post = await this.updatePostMeta({ tags: ids });\n return { post, resolved };\n }\n\n /**\n * Set the post featured image by media attachment ID.\n * Pass 0 to remove the featured image.\n */\n async setFeaturedImage(attachmentId: number): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ featured_media: attachmentId });\n }\n\n /**\n * Set the post publication date (ISO 8601 format).\n * Pass an empty string to clear (WordPress will use the current date).\n */\n async setDate(date: string): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ date: date || null });\n }\n\n /**\n * Set the post URL slug.\n * Note: WordPress may auto-modify the slug to ensure uniqueness (appending -2, -3, etc.).\n */\n async setSlug(slug: string): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ slug });\n }\n\n /**\n * Set whether the post is sticky (pinned to the front page).\n */\n async setSticky(sticky: boolean): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ sticky });\n }\n\n /**\n * Set the post comment status ('open' or 'closed').\n */\n async setCommentStatus(commentStatus: string): Promise<WPPost> {\n this.requireEditablePost();\n return this.updatePostMeta({ comment_status: commentStatus });\n }\n\n // --- Media ---\n\n /**\n * Upload a local file to the WordPress media library.\n * Returns the created media item with ID, URL, and metadata.\n */\n async uploadMedia(\n filePath: string,\n options?: { altText?: string; caption?: string; title?: string },\n ): Promise<WPMediaItem> {\n this.requireState('connected', 'editing');\n\n const fileName = basename(filePath);\n const mimeType = getMimeType(fileName);\n const fileData = await readFile(filePath);\n\n return this.apiClient.uploadMedia(fileData, fileName, mimeType, options);\n }\n\n // --- Notes ---\n\n /**\n * List all notes (block comments) on the current post, along with a map\n * from noteId to the block index where the note is attached.\n */\n async listNotes(): Promise<{ notes: WPNote[]; noteBlockMap: Partial<Record<number, string>> }> {\n this.requireEditablePost();\n if (!this.notesSupported) {\n throw new Error('Notes are not supported. This feature requires WordPress 6.9 or later.');\n }\n\n const notes = await this.apiClient.listNotes(this.currentPost.id);\n\n // Build noteId-to-blockIndex map with a single pass over all blocks\n const noteBlockMap: Record<number, string> = {};\n const blocks = this.documentManager.getBlocks(this.doc);\n const scanBlocks = (blockList: Block[], prefix: string) => {\n for (let i = 0; i < blockList.length; i++) {\n const idx = prefix ? `${prefix}.${i}` : String(i);\n const metadata = blockList[i].attributes.metadata as Record<string, unknown> | undefined;\n if (metadata?.noteId !== null && metadata?.noteId !== undefined) {\n noteBlockMap[metadata.noteId as number] = idx;\n }\n if (blockList[i].innerBlocks.length > 0) {\n scanBlocks(blockList[i].innerBlocks, idx);\n }\n }\n };\n scanBlocks(blocks, '');\n\n return { notes, noteBlockMap };\n }\n\n /**\n * Add a note (block comment) to a specific block.\n * Creates the note via the REST API and sets `metadata.noteId` on the block.\n */\n async addNote(blockIndex: string, content: string): Promise<WPNote> {\n this.requireEditablePost();\n if (!this.notesSupported) {\n throw new Error('Notes are not supported. This feature requires WordPress 6.9 or later.');\n }\n\n const block = this.documentManager.getBlockByIndex(this.doc, blockIndex);\n if (!block) {\n throw new Error(`Block not found at index ${blockIndex}`);\n }\n\n const existingNoteId = (block.attributes.metadata as Record<string, unknown> | undefined)\n ?.noteId;\n if (typeof existingNoteId === 'number' || typeof existingNoteId === 'string') {\n throw new Error(\n `Block at index ${blockIndex} already has a note (ID: ${existingNoteId}). ` +\n `Your view may be stale — call wp_read_post and wp_list_notes to refresh, ` +\n `then use wp_reply_to_note to reply to the existing note.`,\n );\n }\n\n const note = await this.apiClient.createNote({ post: this.currentPost.id, content });\n\n this.doc.transact(() => {\n this.documentManager.setBlockNoteId(this.doc, blockIndex, note.id);\n }, LOCAL_ORIGIN);\n\n this.notifyCommentChange();\n\n if (this._syncClient) {\n this._syncClient.flushQueue();\n }\n\n return note;\n }\n\n /**\n * Reply to an existing note.\n */\n async replyToNote(parentNoteId: number, content: string): Promise<WPNote> {\n this.requireEditablePost();\n if (!this.notesSupported) {\n throw new Error('Notes are not supported. This feature requires WordPress 6.9 or later.');\n }\n\n const reply = await this.apiClient.createNote({\n post: this.currentPost.id,\n content,\n parent: parentNoteId,\n });\n\n this.notifyCommentChange();\n if (this._syncClient) {\n this._syncClient.flushQueue();\n }\n\n return reply;\n }\n\n /**\n * Resolve (delete) a note and remove its metadata linkage from the block.\n */\n async resolveNote(noteId: number): Promise<void> {\n this.requireEditablePost();\n if (!this.notesSupported) {\n throw new Error('Notes are not supported. This feature requires WordPress 6.9 or later.');\n }\n\n // Delete all descendants (replies, replies-to-replies, etc.) then the note itself\n const allNotes = await this.apiClient.listNotes(this.currentPost.id);\n const childrenByParent = new Map<number, number[]>();\n for (const note of allNotes) {\n if (note.parent !== 0) {\n const siblings = childrenByParent.get(note.parent) ?? [];\n siblings.push(note.id);\n childrenByParent.set(note.parent, siblings);\n }\n }\n\n // Collect all descendant IDs via DFS\n const descendantIds: number[] = [];\n const stack = [noteId];\n for (let currentId = stack.pop(); currentId !== undefined; currentId = stack.pop()) {\n const children = childrenByParent.get(currentId);\n if (children) {\n for (const childId of children) {\n descendantIds.push(childId);\n stack.push(childId);\n }\n }\n }\n\n // Delete descendants first (leaves before parents), then the root note\n for (const id of descendantIds.reverse()) {\n await this.apiClient.deleteNote(id);\n }\n await this.apiClient.deleteNote(noteId);\n\n // Find and remove the noteId from whichever block has it\n const blockIndex = this.findBlockIndexByNoteId(noteId);\n if (blockIndex) {\n this.doc.transact(() => {\n this.documentManager.removeBlockNoteId(this.doc, blockIndex);\n }, LOCAL_ORIGIN);\n }\n\n this.notifyCommentChange();\n this.syncClient.flushQueue();\n }\n\n /**\n * Update an existing note's content.\n */\n async updateNote(noteId: number, content: string): Promise<WPNote> {\n this.requireEditablePost();\n if (!this.notesSupported) {\n throw new Error('Notes are not supported. This feature requires WordPress 6.9 or later.');\n }\n\n const updated = await this.apiClient.updateNote(noteId, { content });\n\n this.notifyCommentChange();\n this.syncClient.flushQueue();\n\n return updated;\n }\n\n // --- Status ---\n\n getState(): SessionState {\n return this.state;\n }\n\n getSyncStatus(): {\n isPolling: boolean;\n hasCollaborators: boolean;\n queueSize: number;\n } | null {\n if (!this._syncClient) {\n return null;\n }\n const status = this._syncClient.getStatus();\n return {\n isPolling: status.isPolling,\n hasCollaborators: status.hasCollaborators,\n queueSize: status.queueSize,\n };\n }\n\n getCollaborators(): CollaboratorInfo[] {\n return this.collaborators;\n }\n\n getCurrentPost(): WPPost | null {\n return this._currentPost;\n }\n\n getUser(): WPUser | null {\n return this._user;\n }\n\n getRegistry(): BlockTypeRegistry {\n return this.registry;\n }\n\n getNotesSupported(): boolean {\n return this.notesSupported;\n }\n\n getTitle(): string {\n this.requireEditablePost();\n return this.documentManager.getTitle(this.doc);\n }\n\n // --- Background streaming queue ---\n\n /**\n * Enqueue a streaming function for background processing.\n * The function will be called when all previously queued functions complete.\n * This allows tool calls to return immediately while text streams progressively.\n */\n private enqueueStreaming(fn: () => Promise<void>): void {\n this.streamQueue.push(fn);\n if (!this.streamProcessor) {\n this.streamProcessor = this.processStreamQueue();\n }\n }\n\n /**\n * Process queued streaming functions sequentially.\n * Errors are logged per-entry (block structure is already committed, so\n * partial content is better than stopping the queue).\n */\n private async processStreamQueue(): Promise<void> {\n try {\n while (this.streamQueue.length > 0) {\n const fn = this.streamQueue.shift();\n if (!fn) break;\n try {\n await fn();\n } catch (error) {\n // Block structure is already committed; log and continue\n console.error('Streaming error:', error);\n }\n }\n // Flush after completing all queued streaming to ensure the\n // last chunk of the last item is delivered promptly.\n if (this._syncClient) {\n this._syncClient.flushQueue();\n }\n } finally {\n this.streamProcessor = null;\n }\n }\n\n /**\n * Resolve Y.Text references eagerly and enqueue for background streaming.\n *\n * Block indices are position-based and can shift when concurrent editors\n * insert or remove blocks. By resolving Y.Text references NOW (while the\n * index is known to be valid), the streaming closure writes to the correct\n * Y.Text even if block positions change before it executes.\n */\n private enqueueStreamTargets(targets: StreamTarget[]): void {\n if (targets.length === 0) return;\n\n const resolved: Array<{ ytext: Y.Text; value: string; blockIndex: string }> = [];\n for (const target of targets) {\n let ytext = this.documentManager.getBlockAttributeYText(\n this.doc,\n target.blockIndex,\n target.attrName,\n );\n if (!ytext) {\n // Y.Text doesn't exist yet — create it atomically\n this.doc.transact(() => {\n this.documentManager.updateBlock(this.doc, target.blockIndex, {\n ...(target.attrName === 'content'\n ? { content: '' }\n : { attributes: { [target.attrName]: '' } }),\n });\n }, LOCAL_ORIGIN);\n ytext = this.documentManager.getBlockAttributeYText(\n this.doc,\n target.blockIndex,\n target.attrName,\n );\n }\n if (ytext) {\n resolved.push({ ytext, value: target.value, blockIndex: target.blockIndex });\n }\n }\n\n if (resolved.length > 0) {\n this.enqueueStreaming(async () => {\n for (const { ytext, value, blockIndex } of resolved) {\n await this.streamTextToYText(ytext, value, blockIndex);\n }\n });\n }\n }\n\n /**\n * Wait for all queued streaming to complete.\n * Called by save(), closePost(), and disconnect() to ensure content\n * integrity before persisting or tearing down.\n */\n async drainStreamQueue(): Promise<void> {\n while (this.streamProcessor) {\n await this.streamProcessor;\n }\n }\n\n // --- Streaming internals ---\n\n /**\n * Stream text into a Y.Text in chunks, flushing the sync client between\n * each chunk so the browser sees progressive updates (like fast typing).\n *\n * 1. Compute the delta between the current and target text.\n * 2. Apply retain + delete atomically (old text removed immediately).\n * 3. Split the insert text into HTML-safe chunks (2–6 chars, randomized).\n * 4. For each chunk: apply in its own transaction, flush, and delay.\n */\n private async streamTextToYText(\n ytext: Y.Text,\n newValue: string,\n blockIndex?: string,\n ): Promise<void> {\n const oldValue = ytext.toJSON();\n const delta = computeTextDelta(oldValue, newValue);\n if (!delta) return;\n\n // Set cursor to the block being edited\n if (blockIndex !== undefined) {\n this.updateCursorPosition(blockIndex);\n }\n\n // Apply retain + delete atomically (remove old text immediately)\n if (delta.deleteCount > 0) {\n this.doc.transact(() => {\n const ops: Array<{ retain?: number; delete?: number }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n ops.push({ delete: delta.deleteCount });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n\n this.syncClient.flushQueue();\n }\n\n // If there's nothing to insert, we're done\n if (delta.insertText.length === 0) return;\n\n // For short inserts, apply atomically (no streaming overhead)\n if (delta.insertText.length < STREAM_THRESHOLD) {\n this.doc.transact(() => {\n const ops: Array<{ retain?: number; insert?: string }> = [];\n if (delta.prefixLen > 0) ops.push({ retain: delta.prefixLen });\n ops.push({ insert: delta.insertText });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n return;\n }\n\n // Stream the insert text in chunks.\n // Use Yjs relative positions to track the insertion point so that\n // concurrent edits (e.g., user typing earlier in the block) don't\n // throw off our position. The relative position is created right after\n // inserting a chunk (anchored to a CRDT item), then resolved AFTER the\n // flush+delay when remote edits may have shifted absolute positions.\n let offset = 0;\n let insertPos = delta.prefixLen;\n let nextInsertRelPos: Y.RelativePosition | null = null;\n\n while (offset < delta.insertText.length) {\n // Early exit: bail if session is no longer active (may disconnect mid-stream)\n if (!this._doc || !this._syncClient) return;\n\n // If we have a relative position from the previous chunk, resolve it\n // now (after the delay, when remote edits may have been applied).\n if (nextInsertRelPos) {\n const absPos = Y.createAbsolutePositionFromRelativePosition(nextInsertRelPos, this.doc);\n if (absPos) {\n insertPos = absPos.index;\n }\n }\n\n const chunkSize =\n STREAM_CHUNK_SIZE_MIN +\n Math.floor(Math.random() * (STREAM_CHUNK_SIZE_MAX - STREAM_CHUNK_SIZE_MIN + 1));\n const chunkEnd = findHtmlSafeChunkEnd(delta.insertText, offset, chunkSize);\n const chunk = delta.insertText.slice(offset, chunkEnd);\n\n this.doc.transact(() => {\n const ops: Array<{ retain?: number; insert?: string }> = [];\n if (insertPos > 0) ops.push({ retain: insertPos });\n ops.push({ insert: chunk });\n ytext.applyDelta(ops);\n }, LOCAL_ORIGIN);\n\n // Anchor a relative position at the end of what we just inserted.\n // This tracks the CRDT item, not the absolute offset, so it survives\n // concurrent edits that shift positions.\n insertPos += chunk.length;\n nextInsertRelPos = Y.createRelativePositionFromTypeIndex(ytext, insertPos);\n\n offset = chunkEnd;\n\n // Update cursor to the end of the inserted text so far\n this.updateCursorOffset(insertPos);\n\n // Flush and delay between chunks (but not after the last one)\n if (offset < delta.insertText.length) {\n this.syncClient.flushQueue();\n await new Promise((resolve) => setTimeout(resolve, STREAM_CHUNK_DELAY_MS));\n }\n }\n }\n\n /**\n * Update the awareness cursor to point to a block's Y.Text type.\n * References the Y.Text type itself (not items within it) so the\n * cursor always resolves — even after all Y.Text items are deleted.\n */\n private updateCursorPosition(blockIndex: string): void {\n const ytext = this.documentManager.getBlockContentYText(this.doc, blockIndex);\n if (!ytext) return;\n\n // Get the Y.Text's internal item ID — this references the Y.Text TYPE,\n // not its content items. The type is never deleted, so this always resolves.\n const typeItem = ytext._item;\n if (!typeItem?.id) return;\n\n const relPosJSON = {\n type: { client: typeItem.id.client, clock: typeItem.id.clock },\n tname: null,\n item: null,\n assoc: 0,\n };\n\n // Preserve enteredAt from existing awareness\n const enteredAt = this.awarenessState?.collaboratorInfo.enteredAt ?? Date.now();\n\n this.awarenessState = {\n collaboratorInfo: {\n id: this.user.id,\n name: `${this.user.name ?? this.user.slug} (Claude)`,\n slug: this.user.slug,\n avatar_urls: this.user.avatar_urls ?? {},\n browserType: 'Claude Code MCP',\n enteredAt,\n },\n editorState: {\n selection: {\n type: 'cursor',\n cursorPosition: {\n relativePosition: relPosJSON,\n absoluteOffset: 0,\n },\n },\n },\n };\n }\n\n /**\n * Update just the cursor offset within the current awareness position.\n * Used during streaming to move the cursor forward as text is typed.\n */\n private updateCursorOffset(offset: number): void {\n if (!this.awarenessState?.editorState?.selection) return;\n const selection = this.awarenessState.editorState.selection;\n if (selection.type === 'cursor') {\n selection.cursorPosition.absoluteOffset = offset;\n }\n }\n\n // --- Internal ---\n\n /**\n * Shared helper for metadata updates: call REST API first, then update Y.Doc.\n * REST-first ensures the Y.Doc only reflects committed state — if the API call\n * fails, neither the collaborative doc nor currentPost are modified.\n */\n private async updatePostMeta(fields: Record<string, unknown>): Promise<WPPost> {\n // Persist via REST API first — fail fast before touching collaborative state\n const updated = await this.apiClient.updatePost(this.currentPost.id, fields);\n this._currentPost = updated;\n\n // Update Y.Doc properties to reflect the committed state.\n // Use WordPress-returned values for scalar fields (e.g., slug may be deduplicated),\n // but keep the caller's value for fields where the API returns a different shape\n // (e.g., excerpt returns { rendered, raw } but Y.Doc stores a plain string).\n this.doc.transact(() => {\n for (const [key, value] of Object.entries(fields)) {\n const canonical = (updated as unknown as Record<string, unknown>)[key];\n const useCanonical = canonical !== undefined && typeof canonical === typeof value;\n this.documentManager.setProperty(this.doc, key, useCanonical ? canonical : value);\n }\n }, LOCAL_ORIGIN);\n\n // Flush sync queue so collaborators see the change\n this.syncClient.flushQueue();\n\n return updated;\n }\n\n /**\n * Resolve taxonomy term names to IDs, creating any that don't exist.\n * Uses exact case-insensitive matching (WordPress search is substring-based).\n */\n private async resolveTerms(\n taxonomy: 'categories' | 'tags',\n names: string[],\n ): Promise<Array<{ name: string; id: number; created: boolean }>> {\n const results: Array<{ name: string; id: number; created: boolean }> = [];\n\n for (const name of names) {\n const matches = await this.apiClient.searchTerms(taxonomy, name);\n const exact = matches.find((t) => t.name.toLowerCase() === name.toLowerCase());\n\n if (exact) {\n results.push({ name: exact.name, id: exact.id, created: false });\n } else {\n const created = await this.apiClient.createTerm(taxonomy, name);\n results.push({ name: created.name, id: created.id, created: true });\n }\n }\n\n return results;\n }\n\n /**\n * Signal a note change to other collaborators via the root/comment room.\n * Updates the comment doc's state map (savedAt/savedBy), which triggers\n * other clients to re-fetch notes from the REST API.\n */\n private notifyCommentChange(): void {\n const doc = this.commentDoc;\n if (!doc) return;\n\n doc.transact(() => {\n const stateMap = doc.getMap(CRDT_STATE_MAP_KEY);\n stateMap.set(CRDT_STATE_MAP_SAVED_AT_KEY, Date.now());\n stateMap.set(CRDT_STATE_MAP_SAVED_BY_KEY, doc.clientID);\n }, LOCAL_ORIGIN);\n }\n\n /**\n * Assert that the session is in one of the allowed states.\n */\n private requireState(...allowed: SessionState[]): void {\n if (!allowed.includes(this.state)) {\n throw new Error(\n `Operation requires state ${allowed.join(' or ')}, but current state is '${this.state}'`,\n );\n }\n }\n\n /**\n * Assert that we're in editing state AND the post hasn't been deleted/trashed.\n * Use this instead of `requireState('editing')` for all operations except `closePost()`.\n */\n private requireEditablePost(): void {\n this.requireState('editing');\n if (this.postGone) {\n throw new Error(\n `${this.postGoneReason ?? 'This post is no longer available.'} Use wp_close_post to close it, then open another post.`,\n );\n }\n }\n\n /**\n * Check if the currently open post still exists and is not trashed.\n * Called asynchronously when the sync client reports a 403/404/410 error,\n * or periodically by the health check timer.\n *\n * The in-flight promise is stored in `postGoneCheck` so that `closePost()`\n * can await it before clearing state, preventing stale results from\n * mutating a subsequent session.\n */\n private checkPostStillExists(): void {\n if (this.postGone || this.postGoneCheck || !this._apiClient || !this._currentPost) {\n return;\n }\n const apiClient = this._apiClient;\n const postId = this._currentPost.id;\n this.postGoneCheck = (async () => {\n try {\n const post = await apiClient.getPost(postId);\n if (post.status === 'trash') {\n this.postGone = true;\n this.postGoneReason = 'This post has been moved to the trash.';\n this.stopBackgroundWork();\n }\n } catch (error) {\n if (error instanceof WordPressApiError && (error.status === 404 || error.status === 410)) {\n this.postGone = true;\n this.postGoneReason = 'This post has been deleted.';\n this.stopBackgroundWork();\n }\n } finally {\n this.postGoneCheck = null;\n }\n })();\n }\n\n /**\n * Stop sync polling and the health check timer.\n * Called when `postGone` is confirmed — no point continuing background\n * requests for a post that is known to be deleted/trashed.\n */\n private stopBackgroundWork(): void {\n if (this._syncClient) {\n this._syncClient.stop();\n }\n if (this.postHealthCheckTimer !== null) {\n clearInterval(this.postHealthCheckTimer);\n this.postHealthCheckTimer = null;\n }\n }\n\n /**\n * Returns whether the post has been detected as deleted or trashed.\n */\n isPostGone(): { gone: boolean; reason: string | null } {\n return { gone: this.postGone, reason: this.postGoneReason };\n }\n\n /**\n * Scan all blocks (including nested inner blocks) to find the block\n * whose metadata.noteId matches the given noteId.\n * Returns the block index (dot-notation) or null if not found.\n */\n private findBlockIndexByNoteId(noteId: number): string | null {\n const blocks = this.documentManager.getBlocks(this.doc);\n const scan = (blockList: Block[], prefix: string): string | null => {\n for (let i = 0; i < blockList.length; i++) {\n const idx = prefix ? `${prefix}.${i}` : String(i);\n const metadata = blockList[i].attributes.metadata as Record<string, unknown> | undefined;\n if (metadata?.noteId === noteId) return idx;\n if (blockList[i].innerBlocks.length > 0) {\n const found = scan(blockList[i].innerBlocks, idx);\n if (found) return found;\n }\n }\n return null;\n };\n return scan(blocks, '');\n }\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerConnectTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_connect',\n {\n description:\n 'Connect to a WordPress site for collaborative editing. Not needed if the server was started with WP_SITE_URL, WP_USERNAME, and WP_APP_PASSWORD environment variables — check wp_status first.',\n inputSchema: {\n siteUrl: z.string().describe('WordPress site URL (e.g., https://example.com)'),\n username: z.string().describe('WordPress username'),\n appPassword: z.string().describe('WordPress Application Password'),\n },\n },\n async ({ siteUrl, username, appPassword }) => {\n const state = session.getState();\n if (state !== 'disconnected') {\n const user = session.getUser();\n const userName = user?.name ?? 'unknown';\n return {\n content: [\n {\n type: 'text' as const,\n text: `Already connected as ${userName}. Use wp_disconnect first to reconnect to a different site.`,\n },\n ],\n };\n }\n\n try {\n const user = await session.connect({ siteUrl, username, appPassword });\n return {\n content: [\n {\n type: 'text' as const,\n text: `Connected to ${siteUrl} as ${user.name ?? 'unknown'} (ID: ${user.id})`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_disconnect',\n { description: 'Disconnect from the WordPress site' },\n async () => {\n await session.disconnect();\n return {\n content: [{ type: 'text' as const, text: 'Disconnected from WordPress.' }],\n };\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerPostTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_list_posts',\n {\n description:\n 'List WordPress posts with optional filters. By default, this shows published posts; specify a status filter if you want to see drafts or other non-published posts.',\n inputSchema: {\n status: z\n .string()\n .optional()\n .describe('Filter by post status (e.g., publish, draft, pending)'),\n search: z.string().optional().describe('Search posts by keyword'),\n perPage: z.number().optional().describe('Number of posts to return (default 10)'),\n },\n },\n async ({ status, search, perPage }) => {\n try {\n const posts = await session.listPosts({ status, search, perPage });\n if (posts.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No posts found.' }],\n };\n }\n\n const lines = posts.map(\n (post, i) =>\n `${i + 1}. [${post.id}] ${post.title.raw ?? post.title.rendered} (${post.status})`,\n );\n\n return {\n content: [\n {\n type: 'text' as const,\n text: `Found ${posts.length} posts:\\n\\n${lines.join('\\n')}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to list posts: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_open_post',\n {\n description: 'Open a WordPress post for collaborative editing',\n inputSchema: {\n postId: z.number().describe('The post ID to open'),\n },\n },\n async ({ postId }) => {\n try {\n await session.openPost(postId);\n const content = session.readPost();\n return {\n content: [\n {\n type: 'text' as const,\n text: `Opened post ${postId} for editing.\\n\\n${content}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to open post: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_close_post',\n {\n description: 'Close the current post and stop syncing, without disconnecting from WordPress',\n },\n async () => {\n try {\n await session.closePost();\n return {\n content: [\n {\n type: 'text' as const,\n text: 'Post closed. You can now open another post with wp_open_post or wp_create_post.',\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to close post: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_create_post',\n {\n description: 'Create a new WordPress post and open it for editing',\n inputSchema: {\n title: z.string().optional().describe('Post title'),\n content: z.string().optional().describe('Initial post content (Gutenberg HTML)'),\n },\n },\n async ({ title, content }) => {\n try {\n const post = await session.createPost({ title, content });\n const rendered = session.readPost();\n return {\n content: [\n {\n type: 'text' as const,\n text: `Created and opened post ${post.id}.\\n\\n${rendered}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to create post: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerReadTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_read_post',\n { description: 'Read the current post content as a block listing' },\n () => {\n try {\n const content = session.readPost();\n return {\n content: [{ type: 'text' as const, text: content }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to read post: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_read_block',\n {\n description:\n 'Read a specific block by index (supports dot notation for nested blocks, e.g., \"2.1\")',\n inputSchema: {\n index: z.string().describe('Block index (e.g., \"0\", \"2.1\" for nested blocks)'),\n },\n },\n ({ index }) => {\n try {\n const content = session.readBlock(index);\n return {\n content: [{ type: 'text' as const, text: content }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to read block: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager, BlockInput } from '../session/session-manager.js';\n\nconst blockTypeDescription =\n 'Block type name (e.g., \"core/paragraph\", \"core/heading\", \"core/separator\")';\n\nconst blockInputSchema: z.ZodType<BlockInput> = z.object({\n name: z.string().describe(blockTypeDescription),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z\n .lazy(() => z.array(blockInputSchema))\n .optional()\n .describe('Nested child blocks (e.g., list-items inside a list)'),\n});\n\nexport function registerEditTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_update_block',\n {\n description: \"Update a block's content and/or attributes\",\n inputSchema: {\n index: z.string().describe('Block index (e.g., \"0\", \"2.1\" for nested blocks)'),\n content: z.string().optional().describe('New text content for the block'),\n attributes: z\n .record(z.unknown())\n .optional()\n .describe('Attributes to update (key-value pairs)'),\n },\n },\n ({ index, content, attributes }) => {\n try {\n session.updateBlock(index, { content, attributes });\n return {\n content: [{ type: 'text' as const, text: `Updated block ${index}.` }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to update block: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_insert_block',\n {\n description:\n 'Insert a new block at a position in the post. Supports nested blocks via innerBlocks.',\n inputSchema: {\n position: z.number().describe('Position to insert the block (0-based index)'),\n name: z.string().describe(blockTypeDescription),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z\n .array(blockInputSchema)\n .optional()\n .describe('Nested child blocks (e.g., list-items inside a list)'),\n },\n },\n ({ position, name, content, attributes, innerBlocks }) => {\n try {\n session.insertBlock(position, { name, content, attributes, innerBlocks });\n return {\n content: [\n { type: 'text' as const, text: `Inserted ${name} block at position ${position}.` },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to insert block: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_insert_inner_block',\n {\n description:\n 'Insert a block as a child of an existing block (e.g., add a list-item to a list)',\n inputSchema: {\n parentIndex: z\n .string()\n .describe('Dot-notation index of the parent block (e.g., \"0\", \"2.1\")'),\n position: z.number().describe(\"Position within the parent's inner blocks (0-based)\"),\n name: z.string().describe(blockTypeDescription),\n content: z.string().optional().describe('Text content for the block'),\n attributes: z.record(z.unknown()).optional().describe('Block attributes (key-value pairs)'),\n innerBlocks: z.array(blockInputSchema).optional().describe('Nested child blocks'),\n },\n },\n ({ parentIndex, position, name, content, attributes, innerBlocks }) => {\n try {\n session.insertInnerBlock(parentIndex, position, {\n name,\n content,\n attributes,\n innerBlocks,\n });\n return {\n content: [\n {\n type: 'text' as const,\n text: `Inserted ${name} as inner block at ${parentIndex}.${position}.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to insert inner block: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_remove_blocks',\n {\n description: 'Remove one or more blocks from the post',\n inputSchema: {\n startIndex: z.number().describe('Index of the first block to remove'),\n count: z.number().optional().describe('Number of blocks to remove (default 1)'),\n },\n },\n ({ startIndex, count }) => {\n try {\n const removeCount = count ?? 1;\n session.removeBlocks(startIndex, removeCount);\n return {\n content: [\n {\n type: 'text' as const,\n text: `Removed ${removeCount} block${removeCount !== 1 ? 's' : ''} starting at index ${startIndex}.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to remove blocks: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_remove_inner_blocks',\n {\n description: 'Remove inner blocks from a parent block',\n inputSchema: {\n parentIndex: z.string().describe('Dot-notation index of the parent block (e.g., \"0\")'),\n startIndex: z.number().describe('Index of the first inner block to remove'),\n count: z.number().optional().describe('Number of inner blocks to remove (default 1)'),\n },\n },\n ({ parentIndex, startIndex, count }) => {\n try {\n const removeCount = count ?? 1;\n session.removeInnerBlocks(parentIndex, startIndex, removeCount);\n return {\n content: [\n {\n type: 'text' as const,\n text: `Removed ${removeCount} inner block${removeCount !== 1 ? 's' : ''} from block ${parentIndex}.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to remove inner blocks: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_move_block',\n {\n description: 'Move a block from one position to another',\n inputSchema: {\n fromIndex: z.number().describe('Current position of the block'),\n toIndex: z.number().describe('Target position for the block'),\n },\n },\n ({ fromIndex, toIndex }) => {\n try {\n session.moveBlock(fromIndex, toIndex);\n return {\n content: [\n {\n type: 'text' as const,\n text: `Moved block from position ${fromIndex} to ${toIndex}.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to move block: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_replace_blocks',\n {\n description:\n 'Replace a range of blocks with new blocks. Supports nested blocks via innerBlocks.',\n inputSchema: {\n startIndex: z.number().describe('Index of the first block to replace'),\n count: z.number().describe('Number of blocks to replace'),\n blocks: z\n .array(blockInputSchema)\n .describe('New blocks to insert in place of the removed ones'),\n },\n },\n ({ startIndex, count, blocks }) => {\n try {\n session.replaceBlocks(startIndex, count, blocks);\n return {\n content: [\n {\n type: 'text' as const,\n text: `Replaced ${count} block${count !== 1 ? 's' : ''} at index ${startIndex} with ${blocks.length} new block${blocks.length !== 1 ? 's' : ''}.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to replace blocks: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_edit_block_text',\n {\n description:\n 'Make surgical find-and-replace text edits within a block. ' +\n 'More efficient than wp_update_block for small corrections (typos, ' +\n 'grammar fixes) — only the targeted text is changed, preserving concurrent edits.',\n inputSchema: {\n index: z.string().describe('Block index (e.g., \"0\", \"2.1\" for nested blocks)'),\n attribute: z\n .string()\n .optional()\n .describe(\n 'Rich-text attribute to edit (default: \"content\"). ' +\n 'Use \"citation\" for quote/pullquote citations, \"value\" for pullquote text, etc.',\n ),\n edits: z\n .array(\n z.object({\n find: z\n .string()\n .min(1)\n .describe(\n 'Exact text to find in the current content (may include HTML tags like <strong>, <a href=\"...\">)',\n ),\n replace: z\n .string()\n .describe('Replacement text (empty string to delete the found text)'),\n occurrence: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n 'Which occurrence to replace (1-indexed, default 1). Use when the same text appears multiple times.',\n ),\n }),\n )\n .min(1)\n .describe('List of find-and-replace operations applied sequentially'),\n },\n },\n ({ index, attribute, edits }) => {\n try {\n const result = session.editBlockText(index, edits, attribute);\n\n const lines: string[] = [];\n if (result.failedCount > 0) {\n lines.push(\n `Applied ${result.appliedCount}/${result.edits.length} edit${result.edits.length !== 1 ? 's' : ''}.`,\n );\n for (const edit of result.edits) {\n if (!edit.applied) {\n lines.push(` FAILED: find \"${edit.find}\" — ${edit.error}`);\n }\n }\n } else {\n lines.push(`Applied ${result.appliedCount} edit${result.appliedCount !== 1 ? 's' : ''}.`);\n }\n\n // Include the updated block rendering for verification\n const updated = session.readBlock(index);\n lines.push('');\n lines.push(updated);\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n isError: result.appliedCount === 0 && result.failedCount > 0,\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to edit block text: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_title',\n {\n description: 'Set the post title',\n inputSchema: {\n title: z.string().describe('New post title'),\n },\n },\n ({ title }) => {\n try {\n session.setTitle(title);\n return {\n content: [{ type: 'text' as const, text: `Title set to \"${title}\".` }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to set title: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerStatusTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_status',\n { description: 'Show current connection state, sync status, and post info' },\n () => {\n const state = session.getState();\n const lines: string[] = [];\n\n if (state === 'disconnected') {\n lines.push('Connection: disconnected');\n lines.push('');\n lines.push('Use wp_connect to connect to a WordPress site.');\n } else {\n const user = session.getUser();\n lines.push('Connection: connected');\n lines.push(`User: ${user?.name ?? 'unknown'} (ID: ${user?.id ?? '?'})`);\n\n lines.push(\n `Notes: ${session.getNotesSupported() ? 'supported' : 'not supported (requires WordPress 6.9+)'}`,\n );\n\n const post = session.getCurrentPost();\n if (state === 'editing' && post) {\n const postGoneInfo = session.isPostGone();\n if (postGoneInfo.gone) {\n lines.push(`WARNING: ${postGoneInfo.reason ?? 'This post is no longer available.'}`);\n lines.push('Use wp_close_post to close it, then open another post.');\n lines.push(`Post: (ID: ${post.id})`);\n } else {\n const syncStatus = session.getSyncStatus();\n const collaboratorCount = session.getCollaborators().length;\n\n lines.push(\n `Sync: ${syncStatus?.isPolling ? 'polling' : 'stopped'} (${collaboratorCount + 1} collaborator${collaboratorCount + 1 !== 1 ? 's' : ''})`,\n );\n lines.push(`Post: \"${session.getTitle()}\" (ID: ${post.id}, status: ${post.status})`);\n lines.push(`Queue: ${syncStatus?.queueSize ?? 0} pending updates`);\n }\n } else {\n lines.push('Post: none open');\n lines.push('');\n lines.push('Use wp_open_post or wp_create_post to start editing.');\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n server.registerTool(\n 'wp_collaborators',\n { description: 'List active collaborators on the current post' },\n () => {\n try {\n const state = session.getState();\n if (state !== 'editing') {\n return {\n content: [{ type: 'text' as const, text: 'No post is currently open for editing.' }],\n isError: true,\n };\n }\n\n const collaborators = session.getCollaborators();\n const user = session.getUser();\n\n const lines: string[] = ['Active collaborators:'];\n\n // Add ourselves first\n if (user) {\n lines.push(`- ${user.name} (AI, Claude Code MCP)`);\n }\n\n // Add remote collaborators\n for (const collab of collaborators) {\n lines.push(`- ${collab.name} (Human, ${collab.browserType})`);\n }\n\n if (collaborators.length === 0 && !user) {\n lines.push('- No collaborators detected');\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to get collaborators: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool('wp_save', { description: 'Save the current post' }, async () => {\n try {\n await session.save();\n return {\n content: [\n {\n type: 'text' as const,\n text: `Post \"${session.getTitle()}\" saved.`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to save: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n });\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\nimport type { BlockTypeInfo } from '../yjs/block-type-registry.js';\n\n/**\n * Format a single block type's info for display.\n */\nfunction formatBlockTypeInfo(info: BlockTypeInfo): string {\n const lines: string[] = [];\n lines.push(`${info.name} — ${info.title}`);\n\n if (info.attributes.length > 0) {\n lines.push(' Attributes:');\n for (const attr of info.attributes) {\n let desc = ` ${attr.name} (${attr.type})`;\n if (attr.richText) desc += ' [rich-text]';\n if (attr.default !== undefined) desc += ` default=${JSON.stringify(attr.default)}`;\n lines.push(desc);\n }\n } else {\n lines.push(' Attributes: (none)');\n }\n\n if (info.parent) {\n lines.push(` Parent: ${info.parent.join(', ')}`);\n }\n if (info.ancestor) {\n lines.push(` Ancestor: ${info.ancestor.join(', ')}`);\n }\n if (info.allowedBlocks) {\n lines.push(` Allowed inner blocks: ${info.allowedBlocks.join(', ')}`);\n }\n if (info.supportsInnerBlocks) {\n lines.push(' Supports InnerBlocks: yes');\n }\n\n return lines.join('\\n');\n}\n\nexport function registerBlockTypeTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_block_types',\n {\n description:\n 'Look up block type schemas — attributes, defaults, nesting constraints. Use before inserting unfamiliar block types.',\n inputSchema: {\n name: z\n .string()\n .optional()\n .describe('Exact block type name (e.g., \"core/pullquote\") for full details'),\n search: z\n .string()\n .optional()\n .describe('Search block types by name (e.g., \"quote\", \"media\")'),\n },\n },\n ({ name, search }) => {\n try {\n const registry = session.getRegistry();\n\n if (registry.isUsingFallback()) {\n const state = session.getState();\n const hint =\n state === 'disconnected'\n ? 'Connect to a WordPress site to load full block schemas.'\n : 'Full block schemas could not be loaded. Try disconnecting and reconnecting.';\n return {\n content: [\n {\n type: 'text' as const,\n text: `Block type registry is using fallback data. Only basic block type information is available. ${hint}`,\n },\n ],\n };\n }\n\n // Exact lookup by name\n if (name) {\n const info = registry.getBlockTypeInfo(name);\n if (!info) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Block type \"${name}\" not found. Use search to find block types.`,\n },\n ],\n isError: true,\n };\n }\n return {\n content: [{ type: 'text' as const, text: formatBlockTypeInfo(info) }],\n };\n }\n\n // Search by substring\n if (search) {\n const results = registry.searchBlockTypes(search);\n if (results.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No block types matching \"${search}\".`,\n },\n ],\n };\n }\n const text = results.map((r) => `${r.name} — ${r.title}`).join('\\n');\n return {\n content: [\n {\n type: 'text' as const,\n text: `Found ${results.length} block type${results.length !== 1 ? 's' : ''}:\\n${text}`,\n },\n ],\n };\n }\n\n // No arguments: list all block type names\n const allNames = registry.getKnownBlockTypeNames();\n return {\n content: [\n {\n type: 'text' as const,\n text: `${allNames.length} registered block types:\\n${allNames.join('\\n')}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to look up block types: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\nimport { getMediaCategory } from '../wordpress/mime-types.js';\nimport type { WPMediaItem } from '../wordpress/types.js';\n\n/**\n * Build a block insertion hint based on the uploaded media's MIME type.\n * Shows the primary block type with the exact attributes needed,\n * plus alternative block types that also accept this media category.\n */\nfunction buildInsertionHint(media: WPMediaItem): string {\n const category = getMediaCategory(media.mime_type);\n const lines: string[] = [];\n\n switch (category) {\n case 'image': {\n const imageAttrs: Record<string, unknown> = { id: media.id, url: media.source_url };\n if (media.alt_text) imageAttrs.alt = media.alt_text;\n lines.push('To insert as a block, use wp_insert_block with:');\n lines.push(` name: \"core/image\", attributes: ${JSON.stringify(imageAttrs)}`);\n lines.push(\n 'Other blocks that accept images: core/cover (id + url), core/media-text (mediaId + mediaUrl + mediaType: \"image\")',\n );\n break;\n }\n case 'video':\n lines.push('To insert as a block, use wp_insert_block with:');\n lines.push(\n ` name: \"core/video\", attributes: { \"id\": ${media.id}, \"src\": \"${media.source_url}\" }`,\n );\n lines.push(\n 'Other blocks that accept videos: core/cover (id + url + backgroundType: \"video\"), core/media-text (mediaId + mediaUrl + mediaType: \"video\")',\n );\n break;\n case 'audio':\n lines.push('To insert as a block, use wp_insert_block with:');\n lines.push(\n ` name: \"core/audio\", attributes: { \"id\": ${media.id}, \"src\": \"${media.source_url}\" }`,\n );\n break;\n default:\n lines.push('To insert as a block, use wp_insert_block with:');\n lines.push(\n ` name: \"core/file\", attributes: { \"id\": ${media.id}, \"href\": \"${media.source_url}\" }`,\n );\n break;\n }\n\n return lines.join('\\n');\n}\n\nexport function registerMediaTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_upload_media',\n {\n description:\n 'Upload a local file to the WordPress media library. Returns the attachment ID and URL for use with wp_insert_block (e.g., core/image, core/video, core/audio, core/file).',\n inputSchema: {\n filePath: z.string().describe('Absolute path to the local file to upload'),\n altText: z\n .string()\n .optional()\n .describe('Alt text for the media (important for image accessibility)'),\n title: z.string().optional().describe('Title for the media item'),\n caption: z.string().optional().describe('Caption for the media item'),\n },\n },\n async ({ filePath, altText, title, caption }) => {\n try {\n const media = await session.uploadMedia(filePath, { altText, title, caption });\n const lines = [\n 'Uploaded successfully.',\n '',\n `Attachment ID: ${media.id}`,\n `URL: ${media.source_url}`,\n `MIME type: ${media.mime_type}`,\n ];\n\n if (media.alt_text) {\n lines.push(`Alt text: ${media.alt_text}`);\n }\n\n if (media.media_details.width && media.media_details.height) {\n lines.push(`Dimensions: ${media.media_details.width}x${media.media_details.height}`);\n }\n\n lines.push('');\n lines.push(buildInsertionHint(media));\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to upload media: ${error instanceof Error ? error.message : String(error)}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerNoteTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_list_notes',\n {\n description:\n 'List all notes (block comments) on the currently open post. Returns note content, author, date, and which block each note is attached to. Replies are nested under their parent notes.',\n },\n async () => {\n try {\n const { notes, noteBlockMap } = await session.listNotes();\n if (notes.length === 0) {\n return { content: [{ type: 'text' as const, text: 'No notes on this post.' }] };\n }\n // Group: top-level notes (parent === 0) and replies (nested at any depth)\n const topLevel = notes.filter((n) => n.parent === 0);\n const replyMap = new Map<number, typeof notes>();\n for (const note of notes) {\n if (note.parent !== 0) {\n const list = replyMap.get(note.parent) ?? [];\n list.push(note);\n replyMap.set(note.parent, list);\n }\n }\n\n const lines: string[] = [];\n const stripHtml = (html: string) => html.replace(/<[^>]*>/g, '');\n const renderReplies = (parentId: number, depth: number) => {\n const replies = replyMap.get(parentId) ?? [];\n const indent = ' '.repeat(depth);\n for (const reply of replies) {\n lines.push(`${indent}Reply #${reply.id} by ${reply.author_name} — ${reply.date}`);\n const replyContent = reply.content.raw ?? stripHtml(reply.content.rendered);\n lines.push(`${indent} \"${replyContent}\"`);\n renderReplies(reply.id, depth + 1);\n }\n };\n\n for (const note of topLevel) {\n const blockIdx = noteBlockMap[note.id];\n const blockInfo = blockIdx !== undefined ? ` (block [${blockIdx}])` : ' (unlinked)';\n lines.push(`Note #${note.id} by ${note.author_name}${blockInfo} — ${note.date}`);\n const rawContent = note.content.raw ?? stripHtml(note.content.rendered);\n lines.push(` \"${rawContent}\"`);\n renderReplies(note.id, 1);\n lines.push('');\n }\n return { content: [{ type: 'text' as const, text: lines.join('\\n').trim() }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to list notes: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_add_note',\n {\n description:\n 'Add a note (block comment) to a specific block. Notes are editorial feedback visible in the WordPress editor but not shown to site visitors.',\n inputSchema: {\n blockIndex: z.string().describe('Block index (e.g. \"0\", \"2.1\" for nested blocks)'),\n content: z.string().describe('Note text'),\n },\n },\n async ({ blockIndex, content }) => {\n try {\n const note = await session.addNote(blockIndex, content);\n return {\n content: [\n { type: 'text' as const, text: `Added note #${note.id} to block [${blockIndex}].` },\n ],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to add note: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_reply_to_note',\n {\n description: 'Reply to an existing note. Replies are threaded under the parent note.',\n inputSchema: {\n noteId: z.number().describe('ID of the note to reply to'),\n content: z.string().describe('Reply text'),\n },\n },\n async ({ noteId, content }) => {\n try {\n const reply = await session.replyToNote(noteId, content);\n return {\n content: [\n { type: 'text' as const, text: `Added reply #${reply.id} to note #${noteId}.` },\n ],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to reply to note: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_resolve_note',\n {\n description: 'Resolve (delete) a note and remove its association from the linked block.',\n inputSchema: {\n noteId: z.number().describe('ID of the note to resolve'),\n },\n },\n async ({ noteId }) => {\n try {\n await session.resolveNote(noteId);\n return { content: [{ type: 'text' as const, text: `Resolved note #${noteId}.` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to resolve note: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_update_note',\n {\n description: 'Update the content of an existing note.',\n inputSchema: {\n noteId: z.number().describe('ID of the note to update'),\n content: z.string().describe('New note text'),\n },\n },\n async ({ noteId, content }) => {\n try {\n await session.updateNote(noteId, content);\n return { content: [{ type: 'text' as const, text: `Updated note #${noteId}.` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to update note: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nconst validStatuses = ['draft', 'pending', 'publish', 'private', 'future'] as const;\n\nfunction formatTermList(\n terms: Array<{ name: string; id: number; count?: number; parent?: number }>,\n): string {\n if (terms.length === 0) return 'None found.';\n return terms\n .map((t) => {\n const parts = [t.name];\n if (t.count !== undefined) parts.push(`${t.count} post${t.count !== 1 ? 's' : ''}`);\n return parts.join(' — ');\n })\n .join('\\n');\n}\n\nexport function registerMetadataTools(server: McpServer, session: SessionManager): void {\n server.registerTool(\n 'wp_list_categories',\n {\n description:\n 'List existing categories on the WordPress site. Use this before wp_set_categories to find appropriate existing categories.',\n inputSchema: {\n search: z.string().optional().describe('Filter categories by name'),\n },\n },\n async ({ search }) => {\n try {\n const terms = await session.listCategories({ search });\n return {\n content: [{ type: 'text' as const, text: `Categories:\\n${formatTermList(terms)}` }],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to list categories: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_list_tags',\n {\n description:\n 'List existing tags on the WordPress site. Use this before wp_set_tags to find appropriate existing tags.',\n inputSchema: {\n search: z.string().optional().describe('Filter tags by name'),\n },\n },\n async ({ search }) => {\n try {\n const terms = await session.listTags({ search });\n return { content: [{ type: 'text' as const, text: `Tags:\\n${formatTermList(terms)}` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to list tags: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_status',\n {\n description:\n 'Change the post publication status. Use \"future\" with wp_set_date to schedule a post.',\n inputSchema: {\n status: z.enum(validStatuses).describe('New post status'),\n },\n },\n async ({ status }) => {\n try {\n const oldStatus = session.getCurrentPost()?.status ?? 'unknown';\n await session.setPostStatus(status);\n return {\n content: [\n { type: 'text' as const, text: `Status changed from \"${oldStatus}\" to \"${status}\".` },\n ],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set status: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_categories',\n {\n description:\n \"Set the post categories by name (replaces all existing categories). Creates categories that don't exist yet. WordPress requires at least one category.\",\n inputSchema: {\n categories: z\n .array(z.string())\n .min(1)\n .describe('Category names to assign (e.g., [\"Tech\", \"News\"])'),\n },\n },\n async ({ categories }) => {\n try {\n const { resolved } = await session.setCategories(categories);\n const parts = resolved.map((r) => (r.created ? `${r.name} (created)` : r.name));\n return {\n content: [{ type: 'text' as const, text: `Categories set: ${parts.join(', ')}.` }],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set categories: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_tags',\n {\n description:\n \"Set the post tags by name (replaces all existing tags). Creates tags that don't exist yet. Pass an empty array to remove all tags.\",\n inputSchema: {\n tags: z.array(z.string()).describe('Tag names to assign (e.g., [\"tutorial\", \"beginner\"])'),\n },\n },\n async ({ tags }) => {\n try {\n if (tags.length === 0) {\n await session.setTags([]);\n return { content: [{ type: 'text' as const, text: 'All tags removed.' }] };\n }\n const { resolved } = await session.setTags(tags);\n const parts = resolved.map((r) => (r.created ? `${r.name} (created)` : r.name));\n return { content: [{ type: 'text' as const, text: `Tags set: ${parts.join(', ')}.` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set tags: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_excerpt',\n {\n description:\n 'Set the post excerpt (short summary shown in feeds and search results). Pass an empty string to clear.',\n inputSchema: {\n excerpt: z.string().describe('Post excerpt text'),\n },\n },\n async ({ excerpt }) => {\n try {\n await session.setExcerpt(excerpt);\n if (!excerpt) {\n return { content: [{ type: 'text' as const, text: 'Excerpt cleared.' }] };\n }\n return { content: [{ type: 'text' as const, text: `Excerpt set.` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set excerpt: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_featured_image',\n {\n description:\n 'Set the post featured image by media attachment ID. Use wp_upload_media first to upload an image and get its ID. Pass 0 to remove the featured image.',\n inputSchema: {\n attachmentId: z\n .number()\n .describe('Media attachment ID (from wp_upload_media), or 0 to remove'),\n },\n },\n async ({ attachmentId }) => {\n try {\n await session.setFeaturedImage(attachmentId);\n if (attachmentId === 0) {\n return { content: [{ type: 'text' as const, text: 'Featured image removed.' }] };\n }\n return {\n content: [\n { type: 'text' as const, text: `Featured image set to attachment ${attachmentId}.` },\n ],\n };\n } catch (err) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to set featured image: ${(err as Error).message}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_date',\n {\n description:\n 'Set the post publication date. Use with wp_set_status(\"future\") to schedule a post. Pass an empty string to reset to the current date.',\n inputSchema: {\n date: z\n .string()\n .describe(\n 'Publication date in ISO 8601 format (e.g., \"2026-04-01T09:00:00\"), or empty string to clear',\n ),\n },\n },\n async ({ date }) => {\n try {\n const updated = await session.setDate(date);\n if (!date) {\n return {\n content: [{ type: 'text' as const, text: 'Publication date reset to default.' }],\n };\n }\n return {\n content: [{ type: 'text' as const, text: `Publication date set to ${updated.date}.` }],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set date: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_slug',\n {\n description:\n 'Set the post URL slug. WordPress may auto-modify the slug to ensure uniqueness.',\n inputSchema: {\n slug: z.string().describe('URL slug (e.g., \"my-custom-url\")'),\n },\n },\n async ({ slug }) => {\n try {\n const updated = await session.setSlug(slug);\n const actualSlug = updated.slug;\n if (actualSlug !== slug) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Slug set to \"${actualSlug}\" (adjusted from \"${slug}\" for uniqueness).`,\n },\n ],\n };\n }\n return { content: [{ type: 'text' as const, text: `Slug set to \"${actualSlug}\".` }] };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set slug: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_sticky',\n {\n description: 'Pin or unpin the post on the front page.',\n inputSchema: {\n sticky: z.boolean().describe('true to pin, false to unpin'),\n },\n },\n async ({ sticky }) => {\n try {\n await session.setSticky(sticky);\n return {\n content: [\n {\n type: 'text' as const,\n text: sticky ? 'Post pinned to front page.' : 'Post unpinned.',\n },\n ],\n };\n } catch (err) {\n return {\n content: [\n { type: 'text' as const, text: `Failed to set sticky: ${(err as Error).message}` },\n ],\n isError: true,\n };\n }\n },\n );\n\n server.registerTool(\n 'wp_set_comment_status',\n {\n description: 'Enable or disable comments on the post.',\n inputSchema: {\n status: z\n .enum(['open', 'closed'])\n .describe('\"open\" to enable comments, \"closed\" to disable'),\n },\n },\n async ({ status }) => {\n try {\n await session.setCommentStatus(status);\n return {\n content: [\n {\n type: 'text' as const,\n text: status === 'open' ? 'Comments enabled.' : 'Comments disabled.',\n },\n ],\n };\n } catch (err) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Failed to set comment status: ${(err as Error).message}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerEditingPrompts(server: McpServer, session: SessionManager): void {\n server.registerPrompt(\n 'edit',\n {\n description:\n 'Edit a WordPress post. Optionally specify an editing focus (tone, structure, expand, condense, rewrite, etc.).',\n argsSchema: {\n editingFocus: z\n .string()\n .optional()\n .describe(\n 'Type of editing: \"tone\", \"structure\", \"expand\", \"condense\", \"rewrite\", or a custom focus',\n ),\n },\n },\n ({ editingFocus }) => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Edit a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to edit a WordPress post. Please connect to WordPress first using wp_connect, then open a post with wp_open_post.',\n },\n },\n ],\n };\n }\n\n if (state === 'connected') {\n return {\n description: 'Edit a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: \"I want to edit a WordPress post. Please open a post with wp_open_post first, then I'll tell you what changes to make.\",\n },\n },\n ],\n };\n }\n\n // state === 'editing'\n const postContent = session.readPost();\n const focusInstruction = editingFocus\n ? `Focus on: ${editingFocus}`\n : \"Ask me what kind of editing I'd like (e.g., tone, structure, expand, condense, rewrite).\";\n\n return {\n description: `Edit \"${session.getTitle()}\"`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Edit the following WordPress post. ${focusInstruction}\n\nHere is the current post content:\n\n${postContent}\n\nAvailable tools:\n- wp_edit_block_text — make targeted find-and-replace corrections within a block (preferred for small edits)\n- wp_update_block — modify an existing block by index (for larger rewrites)\n- wp_insert_block — add a new block\n- wp_remove_blocks — remove blocks\n- wp_replace_blocks — replace a range of blocks\n- wp_move_block — reorder blocks\n- wp_set_title — change the post title\n- wp_set_categories, wp_set_tags — update taxonomy\n- wp_set_excerpt — update the post excerpt\n- wp_read_post — re-read the post after making changes\n\nWork block by block. Do not try to replace the entire post at once. Preserve the overall structure unless restructuring was requested. After completing edits, use wp_save to save the post.`,\n },\n },\n ],\n };\n },\n );\n\n server.registerPrompt(\n 'proofread',\n {\n description:\n 'Proofread a WordPress post for grammar, spelling, punctuation, and style issues.',\n },\n () => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Proofread a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to proofread a WordPress post. Please connect to WordPress first using wp_connect, then open a post with wp_open_post.',\n },\n },\n ],\n };\n }\n\n if (state === 'connected') {\n return {\n description: 'Proofread a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to proofread a WordPress post. Please open a post with wp_open_post first.',\n },\n },\n ],\n };\n }\n\n // state === 'editing'\n const postContent = session.readPost();\n\n return {\n description: `Proofread \"${session.getTitle()}\"`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Proofread the following WordPress post. Fix any grammar, spelling, punctuation, and style issues directly.\n\nHere is the current post content:\n\n${postContent}\n\nInstructions:\n- Use wp_edit_block_text for targeted corrections (typos, spelling, grammar fixes). This is faster and safer for concurrent editing than replacing the full block text.\n- Use wp_update_block only when rewriting a significant portion of a block.\n- Fix grammar, spelling, and punctuation errors.\n- Fix inconsistent capitalization, hyphenation, and number formatting.\n- Fix awkward phrasing or unclear sentences.\n- Any obvious fixes can be performed without asking for clarification, but ask if you're unsure about a change.\n- Do NOT change the meaning, tone, or structure of the content.\n- Do NOT add or remove blocks — only update existing text.\n- Do NOT change the title unless it has a clear error.\n- Work through every block systematically — do not skip any.\n- After completing all fixes, use wp_save to save the post.`,\n },\n },\n ],\n };\n },\n );\n}\n","import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\nimport type { WPNote } from '../wordpress/types.js';\n\nfunction formatNotes(notes: WPNote[], noteBlockMap: Partial<Record<number, string>>): string {\n const topLevel = notes.filter((n) => n.parent === 0);\n const replyMap = new Map<number, WPNote[]>();\n for (const note of notes) {\n if (note.parent !== 0) {\n const list = replyMap.get(note.parent) ?? [];\n list.push(note);\n replyMap.set(note.parent, list);\n }\n }\n\n const lines: string[] = [];\n const stripHtml = (html: string) => html.replace(/<[^>]*>/g, '');\n const renderReplies = (parentId: number, depth: number) => {\n const replies = replyMap.get(parentId) ?? [];\n const indent = ' '.repeat(depth);\n for (const reply of replies) {\n lines.push(`${indent}Reply #${reply.id} by ${reply.author_name} — ${reply.date}`);\n const replyContent = reply.content.raw ?? stripHtml(reply.content.rendered);\n lines.push(`${indent} \"${replyContent}\"`);\n renderReplies(reply.id, depth + 1);\n }\n };\n\n for (const note of topLevel) {\n const blockIdx = noteBlockMap[note.id];\n const blockInfo = blockIdx !== undefined ? ` (block [${blockIdx}])` : ' (unlinked)';\n lines.push(`Note #${note.id} by ${note.author_name}${blockInfo} — ${note.date}`);\n const rawContent = note.content.raw ?? stripHtml(note.content.rendered);\n lines.push(` \"${rawContent}\"`);\n renderReplies(note.id, 1);\n lines.push('');\n }\n return lines.join('\\n').trim();\n}\n\nexport function registerReviewPrompts(server: McpServer, session: SessionManager): void {\n server.registerPrompt(\n 'review',\n {\n description:\n 'Review a WordPress post and leave editorial feedback as notes on individual blocks.',\n },\n () => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Review a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to review a WordPress post. Please connect to WordPress first using wp_connect, then open a post with wp_open_post.',\n },\n },\n ],\n };\n }\n\n if (state === 'connected') {\n return {\n description: 'Review a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to review a WordPress post. Please open a post with wp_open_post first.',\n },\n },\n ],\n };\n }\n\n // state === 'editing'\n const postContent = session.readPost();\n const notesSupported = session.getNotesSupported();\n\n if (!notesSupported) {\n return {\n description: `Review \"${session.getTitle()}\"`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Review the following WordPress post and provide editorial feedback.\n\nNote: This WordPress site does not support notes (requires WordPress 6.9+). Please provide your feedback as a text summary instead.\n\nHere is the current post content:\n\n${postContent}\n\nPlease review for:\n- Clarity and readability\n- Logical flow and structure\n- Factual accuracy concerns\n- Missing information or gaps\n- Tone and audience appropriateness\n- Heading hierarchy and paragraph length\n- Post metadata: are categories, tags, and excerpt set appropriately?\n\nProvide your feedback as a structured summary, written in the same language as the post content.`,\n },\n },\n ],\n };\n }\n\n return {\n description: `Review \"${session.getTitle()}\"`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Review the following WordPress post and leave editorial notes on individual blocks.\n\nHere is the current post content:\n\n${postContent}\n\nInstructions:\n- Use wp_add_note to attach feedback to specific blocks by their index.\n- Each block can have one note. If a block already has a note (marked [has note]), use wp_list_notes to read existing notes and wp_reply_to_note to add your feedback as a reply.\n- Review for: clarity, logical flow, factual accuracy, missing information, tone, audience fit, heading hierarchy, and paragraph length.\n- Also review post metadata: are categories, tags, and excerpt set appropriately?\n- Be specific and actionable in your notes — explain what should change and why.\n- Not every block needs a note — only flag issues worth addressing.\n- Write all notes in the same language as the post content.\n- After leaving all notes, provide a brief summary of your overall assessment.`,\n },\n },\n ],\n };\n },\n );\n\n server.registerPrompt(\n 'respond-to-notes',\n {\n description:\n 'Address editorial notes on a WordPress post — read each note, make the requested changes, and resolve notes when done.',\n },\n async () => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Respond to editorial notes',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to respond to editorial notes on a WordPress post. Please connect to WordPress first using wp_connect, then open a post with wp_open_post.',\n },\n },\n ],\n };\n }\n\n if (state === 'connected') {\n return {\n description: 'Respond to editorial notes',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to respond to editorial notes on a WordPress post. Please open a post with wp_open_post first.',\n },\n },\n ],\n };\n }\n\n // state === 'editing'\n const notesSupported = session.getNotesSupported();\n\n if (!notesSupported) {\n return {\n description: 'Respond to editorial notes',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'This WordPress site does not support notes (requires WordPress 6.9+). There are no notes to respond to.',\n },\n },\n ],\n };\n }\n\n const postContent = session.readPost();\n const { notes, noteBlockMap } = await session.listNotes();\n\n if (notes.length === 0) {\n return {\n description: 'Respond to editorial notes',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'There are no notes on this post. No action needed.',\n },\n },\n ],\n };\n }\n\n const formattedNotes = formatNotes(notes, noteBlockMap);\n\n return {\n description: `Respond to notes on \"${session.getTitle()}\"`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Address the editorial notes on this WordPress post. Read each note, make the requested changes, and resolve notes when done.\n\nHere is the current post content:\n\n${postContent}\n\nHere are the editorial notes:\n\n${formattedNotes}\n\nInstructions:\n- Work through each note one at a time.\n- For each note:\n 1. Read the feedback carefully.\n 2. Use wp_update_block to make the requested changes to the referenced block.\n 3. If the note requires a response or clarification, use wp_reply_to_note.\n 4. Once the note is fully addressed, use wp_resolve_note to mark it done.\n- If a note's feedback doesn't apply or you disagree, use wp_reply_to_note to explain why, then move on without resolving.\n- Write all replies in the same language as the post content.\n- Use wp_read_post to verify your changes after editing.\n- After addressing all notes, use wp_save to save the post.`,\n },\n },\n ],\n };\n },\n );\n}\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { SessionManager } from '../session/session-manager.js';\n\nexport function registerAuthoringPrompts(server: McpServer, session: SessionManager): void {\n server.registerPrompt(\n 'draft',\n {\n description: 'Draft a new WordPress post from a topic or brief.',\n argsSchema: {\n topic: z.string().optional().describe('Topic or brief for the new post'),\n tone: z\n .string()\n .optional()\n .describe('Writing tone (e.g., \"professional\", \"casual\", \"academic\", \"conversational\")'),\n audience: z\n .string()\n .optional()\n .describe('Target audience (e.g., \"developers\", \"beginners\", \"general public\")'),\n },\n },\n ({ topic, tone, audience }) => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Draft a new WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to draft a new WordPress post. Please connect to WordPress first using wp_connect.',\n },\n },\n ],\n };\n }\n\n if (!topic?.trim()) {\n return {\n description: 'Draft a new WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: \"I want to draft a new WordPress post. Ask me what topic I'd like to write about.\",\n },\n },\n ],\n };\n }\n\n const contextLines = [\n `Topic: ${topic}`,\n tone ? `Tone: ${tone}` : null,\n audience ? `Audience: ${audience}` : null,\n ]\n .filter(Boolean)\n .join('\\n');\n\n const preamble =\n state === 'editing'\n ? 'Note: A post is currently open. Use wp_close_post first, then create the new post.\\n\\n'\n : '';\n\n return {\n description: `Draft a new post about: ${topic}`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `${preamble}Draft a new WordPress post with the following details:\n\n${contextLines}\n\nInstructions:\n- Use wp_create_post to create a new draft post with an appropriate title.\n- Build the post using wp_insert_block to add blocks one at a time.\n- Use a variety of block types as appropriate: core/heading, core/paragraph, core/list, core/quote, core/separator, etc.\n- Use wp_block_types to look up unfamiliar block types before using them.\n- Structure the post with a clear introduction, body sections with headings, and a conclusion.\n- Write substantive, well-developed paragraphs — not placeholder text.\n- After writing the content, set up post metadata:\n - Use wp_set_categories and wp_set_tags to categorize the post.\n - Use wp_set_excerpt to write a concise summary for feeds and search results.\n- Use wp_read_post to review the final result, then wp_save to save.`,\n },\n },\n ],\n };\n },\n );\n\n server.registerPrompt(\n 'translate',\n {\n description: 'Translate a WordPress post into another language.',\n argsSchema: {\n language: z\n .string()\n .optional()\n .describe('Target language (e.g., \"Spanish\", \"French\", \"Japanese\", \"zh-CN\")'),\n },\n },\n ({ language }) => {\n const state = session.getState();\n\n if (state === 'disconnected') {\n return {\n description: 'Translate a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to translate a WordPress post. Please connect to WordPress first using wp_connect, then open a post with wp_open_post.',\n },\n },\n ],\n };\n }\n\n if (!language?.trim()) {\n return {\n description: 'Translate a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: \"I want to translate a WordPress post. Ask me what language I'd like to translate it into.\",\n },\n },\n ],\n };\n }\n\n if (state === 'connected') {\n return {\n description: 'Translate a WordPress post',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: 'I want to translate a WordPress post. Please open a post with wp_open_post first.',\n },\n },\n ],\n };\n }\n\n // state === 'editing'\n const postContent = session.readPost();\n\n return {\n description: `Translate \"${session.getTitle()}\" into ${language}`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Translate the following WordPress post into ${language}.\n\nHere is the current post content:\n\n${postContent}\n\nInstructions:\n- Translate the title using wp_set_title.\n- Translate each block's content using wp_update_block, working through blocks in order.\n- If the post has an excerpt, translate it using wp_set_excerpt.\n- Preserve all HTML formatting, links, and block structure exactly.\n- Do NOT add, remove, or reorder blocks.\n- Do NOT change non-text attributes (images, URLs, etc.) unless they contain translatable alt text or captions.\n- Adapt idioms and cultural references naturally rather than translating literally.\n- After completing the translation, use wp_read_post to verify, then wp_save to save.`,\n },\n },\n ],\n };\n },\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { SessionManager } from './session/session-manager.js';\nimport { registerConnectTools } from './tools/connect.js';\nimport { registerPostTools } from './tools/posts.js';\nimport { registerReadTools } from './tools/read.js';\nimport { registerEditTools } from './tools/edit.js';\nimport { registerStatusTools } from './tools/status.js';\nimport { registerBlockTypeTools } from './tools/block-types.js';\nimport { registerMediaTools } from './tools/media.js';\nimport { registerNoteTools } from './tools/notes.js';\nimport { registerMetadataTools } from './tools/metadata.js';\nimport { registerEditingPrompts } from './prompts/editing.js';\nimport { registerReviewPrompts } from './prompts/review.js';\nimport { registerAuthoringPrompts } from './prompts/authoring.js';\n\ndeclare const __PKG_VERSION__: string;\n\nexport const VERSION = typeof __PKG_VERSION__ !== 'undefined' ? __PKG_VERSION__ : '0.0.0-dev';\n\nexport async function startServer(): Promise<void> {\n const session = new SessionManager();\n\n // Auto-connect from env vars if available\n let autoConnected = false;\n const siteUrl = process.env.WP_SITE_URL;\n const username = process.env.WP_USERNAME;\n const appPassword = process.env.WP_APP_PASSWORD;\n\n if (siteUrl && username && appPassword) {\n try {\n await session.connect({ siteUrl, username, appPassword });\n autoConnected = true;\n } catch (e) {\n // Don't fail startup — user can connect via wp_connect tool\n console.error('Auto-connect failed:', e);\n }\n }\n\n // Set instructions based on whether auto-connect succeeded\n const instructions = autoConnected\n ? 'Already connected to WordPress. Do NOT call wp_connect. Use wp_status to check connection state, then wp_open_post or wp_create_post to start editing.'\n : 'Use wp_connect to connect to a WordPress site first, or use wp_status to check connection state.';\n\n const server = new McpServer({ name: 'wpce', version: VERSION }, { instructions });\n\n // Register all tools\n registerConnectTools(server, session);\n registerPostTools(server, session);\n registerReadTools(server, session);\n registerEditTools(server, session);\n registerStatusTools(server, session);\n registerBlockTypeTools(server, session);\n registerMediaTools(server, session);\n registerNoteTools(server, session);\n registerMetadataTools(server, session);\n\n // Register all prompts\n registerEditingPrompts(server, session);\n registerReviewPrompts(server, session);\n registerAuthoringPrompts(server, session);\n\n // Start stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Graceful shutdown: prevent the default SIGTERM/SIGINT behavior (immediate\n // exit) so the MCP SDK can finish responding to any pending shutdown request.\n // Also handle stdin EOF — the StdioServerTransport doesn't detect it, and the\n // SyncClient polling timer would otherwise keep the process alive forever.\n let shutdownInProgress = false;\n\n const cleanup = async () => {\n if (shutdownInProgress) return;\n shutdownInProgress = true;\n\n await session.disconnect();\n await server.close();\n process.exit(0);\n };\n\n process.on('SIGTERM', () => {\n void cleanup();\n });\n process.on('SIGINT', () => {\n void cleanup();\n });\n process.stdin.on('end', () => {\n void cleanup();\n });\n}\n","/**\n * Browser-based WordPress Application Password authorisation flow with\n * localhost HTTP callback.\n *\n * Starts a local HTTP server on 127.0.0.1, opens the browser to WordPress's\n * `authorize-application.php` with a `success_url` pointing back to the local\n * server. When the user approves, WordPress redirects to the callback with\n * `user_login` and `password` query parameters, which are captured\n * automatically.\n *\n * WordPress 7.0+ allows HTTP callbacks to loopback addresses. For older\n * versions, the caller can abort the flow and fall back to the non-callback\n * authorisation page.\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { createServer, type Server } from 'node:http';\nimport { execFile } from 'node:child_process';\nimport type { WpCredentials } from './types.js';\n\n/** Application name shown in the WordPress authorisation UI. */\nexport const APP_NAME = 'Claudaborative Editing';\n\n/**\n * Fixed UUID identifying this application to WordPress.\n * WordPress uses this to track and allow revocation of Application Passwords.\n */\nexport const APP_ID = 'b7e3f1a2-8d4c-4e6f-9a1b-2c3d4e5f6a7b';\n\nexport interface AuthFlowOptions {\n /** Override browser opener for testing. */\n openBrowser?: (url: string) => Promise<void>;\n}\n\nexport interface AuthResult {\n /** Credentials received via callback, or null on abort/rejection. */\n credentials: WpCredentials | null;\n /** Whether the user explicitly rejected the authorisation. */\n rejected: boolean;\n}\n\nexport interface AuthFlowHandle {\n /** The authorisation URL (with callback params) for display to the user. */\n authUrl: string;\n /** Resolves when credentials are received, user rejects, or flow is aborted. */\n result: Promise<AuthResult>;\n /** Abort the flow — resolves the result promise with credentials: null. */\n abort: () => void;\n}\n\nconst SUCCESS_HTML = `<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>Claudaborative Editing</title>\n<style>body{font-family:system-ui,sans-serif;text-align:center;padding:4rem;color:#1e293b;}\nh1{color:#16a34a;}</style></head><body>\n<h1>Authentication successful!</h1>\n<p>You can close this tab and return to your terminal.</p>\n</body></html>`;\n\nconst REJECTED_HTML = `<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"><title>Claudaborative Editing</title>\n<style>body{font-family:system-ui,sans-serif;text-align:center;padding:4rem;color:#1e293b;}\nh1{color:#dc2626;}</style></head><body>\n<h1>Authentication denied</h1>\n<p>The authorisation request was declined. Please return to your terminal.</p>\n</body></html>`;\n\n/**\n * Build the non-callback authorisation URL.\n *\n * Used as a fallback when the callback flow is aborted (pre-WP 7.0).\n * Without `success_url`/`reject_url`, WordPress shows the generated\n * credentials directly on the page for the user to copy.\n */\nexport function buildManualAuthUrl(siteUrl: string): string {\n const params = new URLSearchParams({\n app_name: APP_NAME,\n app_id: APP_ID,\n });\n return `${siteUrl}/wp-admin/authorize-application.php?${params.toString()}`;\n}\n\n/**\n * Start the authorisation flow: local callback server → browser.\n *\n * Returns a handle once the server is listening and the browser has been\n * opened. The caller should race `handle.result` against user input (e.g.,\n * a prompt to switch to manual auth) and call `handle.abort()` to tear\n * down the server if the user opts out.\n */\nexport async function startAuthFlow(\n siteUrl: string,\n options?: AuthFlowOptions,\n): Promise<AuthFlowHandle> {\n const openFn = options?.openBrowser ?? openBrowserDefault;\n\n // Per-flow state token to verify callbacks originated from our auth URL.\n const state = randomBytes(16).toString('hex');\n\n return new Promise<AuthFlowHandle>((resolveHandle, rejectHandle) => {\n let settled = false;\n let resolveResult!: (value: AuthResult) => void;\n\n const resultPromise = new Promise<AuthResult>((resolve) => {\n resolveResult = resolve;\n });\n\n function settle(result: AuthResult): void {\n if (settled) return;\n settled = true;\n server.close();\n server.closeAllConnections();\n resolveResult(result);\n }\n\n const server: Server = createServer((req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n\n if (url.pathname !== '/callback') {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n // Verify the state token to prevent spoofed callbacks from local processes.\n if (url.searchParams.get('state') !== state) {\n res.writeHead(403, { 'Content-Type': 'text/plain' });\n res.end('Invalid state');\n return;\n }\n\n if (url.searchParams.has('rejected')) {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(REJECTED_HTML);\n settle({ credentials: null, rejected: true });\n return;\n }\n\n const userLogin = url.searchParams.get('user_login');\n const password = url.searchParams.get('password');\n\n if (!userLogin || !password) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing credentials');\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(SUCCESS_HTML);\n settle({\n credentials: { siteUrl, username: userLogin, appPassword: password },\n rejected: false,\n });\n });\n\n server.on('error', (err) => {\n // Server failed to start (e.g., permission denied), or post-listen error.\n // Reject the handle promise (no-op if already resolved) and settle the\n // result promise so callers awaiting handle.result aren't left hanging.\n rejectHandle(err);\n settle({ credentials: null, rejected: false });\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n const port = typeof addr === 'object' && addr !== null ? addr.port : 0;\n\n const callbackBase = `http://127.0.0.1:${port}/callback?state=${state}`;\n\n const params = new URLSearchParams({\n app_name: APP_NAME,\n app_id: APP_ID,\n success_url: callbackBase,\n reject_url: `${callbackBase}&rejected=true`,\n });\n\n const authUrl = `${siteUrl}/wp-admin/authorize-application.php?${params.toString()}`;\n\n openFn(authUrl).catch(() => {\n // Browser open failure is non-fatal — the user can visit the URL manually.\n });\n\n resolveHandle({\n authUrl,\n result: resultPromise,\n abort: () => {\n settle({ credentials: null, rejected: false });\n },\n });\n });\n });\n}\n\n/**\n * Open a URL in the system's default browser.\n *\n * Uses platform-specific commands. Does not reject if the browser fails\n * to open — the user can always visit the URL manually.\n */\nexport function openBrowserDefault(url: string): Promise<void> {\n return new Promise((resolve) => {\n const platform = process.platform;\n let command: string;\n let args: string[];\n\n if (platform === 'darwin') {\n command = 'open';\n args = [url];\n } else if (platform === 'win32') {\n command = 'explorer';\n args = [url];\n } else {\n command = 'xdg-open';\n args = [url];\n }\n\n execFile(command, args, (error) => {\n // Intentionally swallowed — the user can manually visit the URL.\n if (error) {\n // Silence: browser open failure is non-fatal.\n }\n resolve();\n });\n });\n}\n","/**\n * MCP client registry — defines supported MCP clients and their configuration paths,\n * detection logic, and optional CLI integration.\n */\n\nimport { execFileSync, execSync } from 'child_process';\nimport { existsSync } from 'fs';\nimport { homedir, platform } from 'os';\nimport { dirname, join } from 'path';\n\nimport type { McpClientConfig, McpClientType, WpCredentials } from './types.js';\n\n/** The server name used in MCP config files and CLI commands. */\nexport const SERVER_NAME = 'wpce';\n\n/**\n * Returns the command to check if an executable exists on PATH,\n * appropriate for the current platform.\n */\nfunction whichCommand(executable: string): string {\n return platform() === 'win32' ? `where ${executable}` : `which ${executable}`;\n}\n\n/** Returns true if the given executable is found on PATH. */\nfunction isOnPath(executable: string): boolean {\n try {\n execSync(whichCommand(executable), { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns the appropriate application data directory base path for the current platform.\n * macOS: ~/Library/Application Support\n * Windows: %APPDATA%\n * Linux: ~/.config\n */\nfunction appDataDir(): string {\n const p = platform();\n const home = homedir();\n\n if (p === 'darwin') {\n return join(home, 'Library', 'Application Support');\n }\n if (p === 'win32') {\n return process.env.APPDATA ?? join(home, 'AppData', 'Roaming');\n }\n return join(home, '.config');\n}\n\n/** Claude Code CLI integration: register the MCP server via `claude mcp add`. */\nfunction claudeCodeUseCli(credentials: WpCredentials): boolean {\n if (!isOnPath('claude')) {\n return false;\n }\n try {\n // Use execFileSync with an args array to avoid shell injection.\n // Credential values may contain spaces, quotes, dollar signs, etc.\n execFileSync(\n 'claude',\n [\n 'mcp',\n 'add',\n '--scope',\n 'user',\n '-e',\n `WP_SITE_URL=${credentials.siteUrl}`,\n '-e',\n `WP_USERNAME=${credentials.username}`,\n '-e',\n `WP_APP_PASSWORD=${credentials.appPassword}`,\n SERVER_NAME,\n '--',\n 'npx',\n 'claudaborative-editing',\n ],\n { stdio: 'ignore' },\n );\n return true;\n } catch {\n return false;\n }\n}\n\n/** Claude Code CLI integration: remove the MCP server via `claude mcp remove`. */\nfunction claudeCodeRemoveCli(): boolean {\n try {\n execFileSync('claude', ['mcp', 'remove', '--scope', 'user', SERVER_NAME], { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Registry of all supported MCP clients. */\nexport const MCP_CLIENTS: Record<McpClientType, McpClientConfig> = {\n 'claude-code': {\n name: 'claude-code',\n displayName: 'Claude Code',\n configPath: () => join(homedir(), '.claude.json'),\n configKey: 'mcpServers',\n detectInstall: () => {\n const configDir = dirname(join(homedir(), '.claude.json'));\n return existsSync(configDir) && isOnPath('claude');\n },\n useCli: claudeCodeUseCli,\n removeCli: claudeCodeRemoveCli,\n },\n\n 'claude-desktop': {\n name: 'claude-desktop',\n displayName: 'Claude Desktop',\n configPath: () => join(appDataDir(), 'Claude', 'claude_desktop_config.json'),\n configKey: 'mcpServers',\n detectInstall: () =>\n existsSync(dirname(join(appDataDir(), 'Claude', 'claude_desktop_config.json'))),\n },\n\n vscode: {\n name: 'vscode',\n displayName: 'VS Code',\n configPath: () => join(appDataDir(), 'Code', 'User', 'mcp.json'),\n configKey: 'servers',\n detectInstall: () => existsSync(dirname(join(appDataDir(), 'Code', 'User', 'mcp.json'))),\n },\n\n 'vscode-insiders': {\n name: 'vscode-insiders',\n displayName: 'VS Code Insiders',\n configPath: () => join(appDataDir(), 'Code - Insiders', 'User', 'mcp.json'),\n configKey: 'servers',\n detectInstall: () =>\n existsSync(dirname(join(appDataDir(), 'Code - Insiders', 'User', 'mcp.json'))),\n },\n\n cursor: {\n name: 'cursor',\n displayName: 'Cursor',\n configPath: () => join(homedir(), '.cursor', 'mcp.json'),\n configKey: 'mcpServers',\n detectInstall: () => existsSync(dirname(join(homedir(), '.cursor', 'mcp.json'))),\n },\n\n windsurf: {\n name: 'windsurf',\n displayName: 'Windsurf',\n configPath: () => join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'),\n configKey: 'mcpServers',\n detectInstall: () =>\n existsSync(dirname(join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'))),\n },\n};\n\n/** Detect which MCP clients are installed on this system. */\nexport function detectInstalledClients(): Array<{\n type: McpClientType;\n config: McpClientConfig;\n detected: boolean;\n}> {\n return (Object.entries(MCP_CLIENTS) as Array<[McpClientType, McpClientConfig]>).map(\n ([type, config]) => ({\n type,\n config,\n detected: config.detectInstall(),\n }),\n );\n}\n","/**\n * Config file reader/writer for MCP client JSON configuration.\n *\n * Handles reading, writing, and merging MCP server entries into\n * JSON config files used by various MCP clients (Claude Desktop,\n * VS Code, Cursor, etc.).\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, renameSync, unlinkSync, existsSync } from 'fs';\nimport { dirname } from 'path';\nimport type { WpCredentials } from './types.js';\n\n/**\n * Read and parse a JSON config file.\n * Returns `{}` if the file doesn't exist (ENOENT).\n * Re-throws all other errors.\n */\nexport function readJsonConfig(filePath: string): Record<string, unknown> {\n try {\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as Record<string, unknown>;\n } catch (err: unknown) {\n if (err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw err;\n }\n}\n\n/**\n * Detect the indentation used in a JSON string.\n * Looks at the first indented line to determine tab vs spaces and count.\n * Defaults to 2 spaces if unable to detect.\n */\nexport function detectIndent(content: string): string {\n const lines = content.split('\\n');\n for (const line of lines) {\n // Find the first line that starts with whitespace (indented)\n const match = /^(\\s+)\\S/.exec(line);\n if (match) {\n const whitespace = match[1];\n if (whitespace.includes('\\t')) {\n return '\\t';\n }\n return whitespace;\n }\n }\n return ' ';\n}\n\n/**\n * Atomically write a JSON config file.\n *\n * Writes to a temp file first, then renames to the final path.\n * Creates parent directories if needed.\n * If `indent` is not provided, tries to detect from existing file content,\n * falling back to 2 spaces.\n */\nexport function writeJsonConfig(\n filePath: string,\n config: Record<string, unknown>,\n indent?: string,\n): void {\n const dir = dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let resolvedIndent = indent;\n if (resolvedIndent === undefined) {\n try {\n const existing = readFileSync(filePath, 'utf-8');\n resolvedIndent = detectIndent(existing);\n } catch {\n resolvedIndent = ' ';\n }\n }\n\n const json = JSON.stringify(config, null, resolvedIndent) + '\\n';\n const tmpPath = `${filePath}.tmp`;\n\n try {\n writeFileSync(tmpPath, json, 'utf-8');\n try {\n renameSync(tmpPath, filePath);\n } catch (err: unknown) {\n // On Windows, renameSync fails when destination exists. Fall back to unlink + rename.\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'EPERM'\n ) {\n unlinkSync(filePath);\n renameSync(tmpPath, filePath);\n } else {\n throw err;\n }\n }\n } finally {\n // Clean up tmp file if it still exists (e.g., rename failed).\n // Credentials are written to tmp, so we must not leave it behind.\n try {\n if (existsSync(tmpPath)) {\n unlinkSync(tmpPath);\n }\n } catch {\n // Best-effort cleanup\n }\n }\n}\n\n/**\n * Add an MCP server entry to a config file.\n *\n * Reads the existing config (or starts with `{}`), ensures the\n * `configKey` object exists, sets `serverName` within it, and\n * writes back preserving existing indentation.\n */\nexport function addServerToConfig(\n configPath: string,\n configKey: string,\n serverName: string,\n serverEntry: Record<string, unknown>,\n): void {\n const config = readJsonConfig(configPath);\n\n if (\n typeof config[configKey] !== 'object' ||\n config[configKey] === null ||\n Array.isArray(config[configKey])\n ) {\n config[configKey] = {};\n }\n\n const servers = config[configKey] as Record<string, unknown>;\n servers[serverName] = serverEntry;\n\n writeJsonConfig(configPath, config);\n}\n\n/**\n * Remove an MCP server entry from a config file.\n *\n * Returns true if the entry was found and removed, false otherwise.\n */\nexport function removeServerFromConfig(\n configPath: string,\n configKey: string,\n serverName: string,\n): boolean {\n const config = readJsonConfig(configPath);\n\n const servers = config[configKey];\n if (typeof servers !== 'object' || servers === null || Array.isArray(servers)) {\n return false;\n }\n\n const serversObj = servers as Record<string, unknown>;\n if (!(serverName in serversObj)) {\n return false;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete serversObj[serverName];\n writeJsonConfig(configPath, config);\n return true;\n}\n\n/**\n * Check if an MCP server entry exists in a config file.\n */\nexport function hasServerInConfig(\n configPath: string,\n configKey: string,\n serverName: string,\n): boolean {\n const config = readJsonConfig(configPath);\n\n const servers = config[configKey];\n if (typeof servers !== 'object' || servers === null || Array.isArray(servers)) {\n return false;\n }\n\n return serverName in (servers as Record<string, unknown>);\n}\n\n/**\n * Build the standard MCP server config entry from WordPress credentials.\n */\nexport function buildServerEntry(credentials: WpCredentials): Record<string, unknown> {\n return {\n command: 'npx',\n args: ['claudaborative-editing'],\n env: {\n WP_SITE_URL: credentials.siteUrl,\n WP_USERNAME: credentials.username,\n WP_APP_PASSWORD: credentials.appPassword,\n },\n };\n}\n","/**\n * Interactive checkbox prompt with keyboard navigation.\n *\n * Renders a list of items the user can navigate with arrow keys,\n * toggle with space, and confirm with enter.\n *\n * Uses `readline.emitKeypressEvents()` to parse terminal escape sequences\n * into structured keypress events, avoiding manual escape-code buffering.\n */\n\nimport { emitKeypressEvents } from 'readline';\n\nexport interface CheckboxItem {\n /** Display label */\n label: string;\n /** Suffix shown after the label (e.g., \"(not detected)\") */\n hint?: string;\n /** Whether this item is initially selected */\n selected: boolean;\n}\n\nexport interface CheckboxOptions {\n /** If true, Enter is blocked when no items are selected (default: false) */\n requireSelection?: boolean;\n}\n\nexport interface CheckboxResult {\n /** Indices of selected items */\n selected: number[];\n}\n\n/**\n * Show an interactive checkbox prompt in the terminal.\n *\n * Uses raw stdin mode to capture keystrokes. Falls back to returning\n * the initial selection if stdin is not a TTY (e.g., piped input).\n *\n * Controls:\n * ↑/↓ or k/j — move cursor\n * space — toggle selection\n * enter — confirm\n * a — select all\n * n — select none\n */\nexport function checkboxPrompt(\n items: CheckboxItem[],\n options?: CheckboxOptions,\n): Promise<CheckboxResult> {\n const requireSelection = options?.requireSelection ?? false;\n\n // Non-interactive fallback: return initial selection\n if (!process.stdin.isTTY) {\n const selected = items.map((item, i) => (item.selected ? i : -1)).filter((i) => i >= 0);\n return Promise.resolve({ selected });\n }\n\n /* v8 ignore start -- interactive TTY code requires a real terminal */\n return new Promise((resolve) => {\n const state = items.map((item) => item.selected);\n // Extra row at the end for the \"Done\" button\n const totalRows = items.length + 1;\n let cursor = 0;\n\n function render(initial: boolean): void {\n // Move cursor up to overwrite previous render (skip on first render)\n if (!initial) {\n process.stdout.write(`\\x1B[${totalRows}A`);\n }\n\n for (let i = 0; i < items.length; i++) {\n const pointer = i === cursor ? '\\x1B[36m❯\\x1B[0m' : ' ';\n const check = state[i] ? '\\x1B[32m✓\\x1B[0m' : ' ';\n const hint = items[i].hint ? ` \\x1B[2m${items[i].hint}\\x1B[0m` : '';\n process.stdout.write(`\\x1B[2K ${pointer} [${check}] ${items[i].label}${hint}\\n`);\n }\n\n // \"Done\" button row\n const count = state.filter(Boolean).length;\n const doneDisabled = requireSelection && count === 0;\n const donePointer = cursor === items.length ? '\\x1B[36m❯\\x1B[0m' : ' ';\n const doneStyle = doneDisabled ? '\\x1B[2m' : '\\x1B[1m';\n const doneSuffix = doneDisabled ? ' (select at least one)' : ` (${count} selected)`;\n process.stdout.write(`\\x1B[2K ${donePointer} ${doneStyle}Done\\x1B[0m${doneSuffix}\\n`);\n }\n\n render(true);\n\n const stdin = process.stdin;\n\n // emitKeypressEvents must be called BEFORE setRawMode.\n // It's safe to call multiple times — it no-ops if already active.\n emitKeypressEvents(stdin);\n stdin.setRawMode(true);\n stdin.resume();\n\n const onKeypress = (_ch: string | undefined, key: KeypressKey | undefined): void => {\n if (!key) {\n return;\n }\n\n // Ctrl-C\n if (key.ctrl && key.name === 'c') {\n stdin.setRawMode(false);\n process.exit(130);\n }\n\n if (key.name === 'up' || key.name === 'k') {\n cursor = cursor > 0 ? cursor - 1 : totalRows - 1;\n render(false);\n } else if (key.name === 'down' || key.name === 'j') {\n cursor = cursor < totalRows - 1 ? cursor + 1 : 0;\n render(false);\n } else if (key.name === 'space') {\n if (cursor < items.length) {\n state[cursor] = !state[cursor];\n render(false);\n }\n } else if (key.name === 'return') {\n const hasSelection = state.some(Boolean);\n if (requireSelection && !hasSelection) {\n // Don't allow confirming with nothing selected\n return;\n }\n finish();\n } else if (key.name === 'a') {\n state.fill(true);\n render(false);\n } else if (key.name === 'n') {\n state.fill(false);\n render(false);\n }\n };\n\n function finish(): void {\n stdin.removeListener('keypress', onKeypress);\n stdin.setRawMode(false);\n stdin.pause();\n\n const selected = state.map((s, i) => (s ? i : -1)).filter((i) => i >= 0);\n resolve({ selected });\n }\n\n stdin.on('keypress', onKeypress);\n });\n /* v8 ignore stop */\n}\n\n/**\n * Node.js keypress event key descriptor.\n * Not exported from @types/node, so we define the subset we use.\n */\ninterface KeypressKey {\n name?: string;\n ctrl?: boolean;\n meta?: boolean;\n shift?: boolean;\n sequence?: string;\n}\n","/**\n * Interactive setup wizard for claudaborative-editing.\n *\n * Collects WordPress credentials (via browser auth or manual entry),\n * validates them, detects installed MCP clients, and configures them.\n */\n\nimport { createInterface } from 'readline';\nimport { WordPressApiClient, WordPressApiError } from '../wordpress/api-client.js';\nimport { startAuthFlow, buildManualAuthUrl, openBrowserDefault } from './auth-server.js';\nimport type { AuthFlowHandle } from './auth-server.js';\nimport { detectInstalledClients, SERVER_NAME } from './clients.js';\nimport {\n addServerToConfig,\n buildServerEntry,\n hasServerInConfig,\n removeServerFromConfig,\n} from './config-writer.js';\nimport { checkboxPrompt } from './checkbox-prompt.js';\nimport type { CheckboxItem, CheckboxOptions, CheckboxResult } from './checkbox-prompt.js';\nimport type { AuthFlowOptions } from './auth-server.js';\nimport type { McpClientConfig, McpClientType, SetupOptions, WpCredentials } from './types.js';\n\nexport interface SetupDeps {\n prompt: (question: string) => Promise<string>;\n /** Prompt for sensitive input, masking characters with '*' */\n promptSecret: (question: string) => Promise<string>;\n log: (message: string) => void;\n error: (message: string) => void;\n exit: (code: number) => never;\n cleanup: () => void;\n /** Override auth flow for testing */\n openAuth?: (siteUrl: string, options?: AuthFlowOptions) => Promise<AuthFlowHandle>;\n /** Override browser opener for testing (used in manual fallback) */\n openBrowser?: (url: string) => Promise<void>;\n /** Override client detection for testing */\n detectClients?: () => Array<{ type: McpClientType; config: McpClientConfig; detected: boolean }>;\n /** Override config writing for testing */\n writeConfig?: (config: McpClientConfig, credentials: WpCredentials) => Promise<boolean>;\n /** Override config removal for testing */\n removeConfig?: (config: McpClientConfig) => Promise<boolean>;\n /** Override config existence check for testing */\n hasConfig?: (config: McpClientConfig) => boolean;\n /** Override interactive checkbox selection for testing */\n selectCheckbox?: (items: CheckboxItem[], options?: CheckboxOptions) => Promise<CheckboxResult>;\n}\n\n/**\n * Read a line from stdin with each character masked as '*'.\n * Uses raw mode to intercept keystrokes before they echo.\n */\nfunction readMasked(question: string): Promise<string> {\n return new Promise((resolve) => {\n process.stdout.write(question);\n\n if (!process.stdin.isTTY) {\n // Non-interactive: fall back to plain readline (e.g., piped input in tests)\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question('', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n return;\n }\n\n /* v8 ignore start -- raw-mode TTY code requires a real terminal */\n const raw = process.stdin;\n raw.setRawMode(true);\n raw.resume();\n raw.setEncoding('utf8');\n\n let input = '';\n let finished = false;\n\n const onData = (chunk: string): void => {\n for (const c of chunk) {\n if (finished) {\n break;\n }\n if (c === '\\n' || c === '\\r') {\n finished = true;\n raw.setRawMode(false);\n raw.pause();\n raw.removeListener('data', onData);\n process.stdout.write('\\n');\n resolve(input.trim());\n } else if (c === '\\u0003') {\n raw.setRawMode(false);\n process.exit(130);\n } else if (c === '\\u007F' || c === '\\b') {\n if (input.length > 0) {\n input = input.slice(0, -1);\n process.stdout.write('\\b \\b');\n }\n } else if (c.charCodeAt(0) >= 32) {\n input += c;\n process.stdout.write('*');\n }\n }\n };\n raw.on('data', onData);\n /* v8 ignore stop */\n });\n}\n\n/* v8 ignore start -- defaultDeps creates real readline/stdin bindings; tests inject deps directly */\nfunction defaultDeps(): SetupDeps {\n let rl = createInterface({ input: process.stdin, output: process.stdout });\n\n function closeRl(): void {\n rl.close();\n }\n\n function reopenRl(): void {\n rl = createInterface({ input: process.stdin, output: process.stdout });\n }\n\n return {\n prompt: (question: string) =>\n new Promise((resolve) => {\n rl.question(question, (answer) => {\n resolve(answer.trim());\n });\n }),\n promptSecret: (question: string) => {\n closeRl();\n return readMasked(question).finally(() => {\n reopenRl();\n });\n },\n log: (msg) => {\n console.log(msg);\n },\n error: (msg) => {\n console.error(`Error: ${msg}`);\n },\n exit: (code) => {\n closeRl();\n return process.exit(code);\n },\n cleanup: () => {\n closeRl();\n },\n selectCheckbox: (items: CheckboxItem[], opts?: CheckboxOptions) => {\n closeRl();\n return checkboxPrompt(items, opts).finally(() => {\n reopenRl();\n });\n },\n };\n}\n/* v8 ignore stop */\n\nexport async function runSetup(\n deps: SetupDeps = defaultDeps(),\n options: SetupOptions = {},\n): Promise<void> {\n if (options.remove) {\n await runRemove(deps);\n return;\n }\n\n deps.log('');\n deps.log('claudaborative-editing setup');\n deps.log('============================');\n deps.log('');\n deps.log('Prerequisites:');\n deps.log(' - WordPress 7.0+ with collaborative editing enabled');\n deps.log(' (Settings → Writing in your WordPress admin)');\n deps.log('');\n\n // 1. Collect credentials (browser or manual)\n const credentials = await collectCredentials(deps, options);\n\n // 2. Validate credentials\n await validateCredentials(deps, credentials);\n\n // 3. Detect and select clients\n const selectedClients = await detectAndSelectClients(deps, options);\n\n // 4. Configure selected clients\n await configureClients(deps, credentials, selectedClients);\n\n deps.log('');\n deps.log('Done! Restart your MCP clients to start editing.');\n\n deps.cleanup();\n}\n\n// ---------------------------------------------------------------------------\n// Credential collection\n// ---------------------------------------------------------------------------\n\nasync function collectCredentials(deps: SetupDeps, options: SetupOptions): Promise<WpCredentials> {\n if (options.manual || options.client) {\n return collectManualCredentials(deps);\n }\n return collectBrowserCredentials(deps);\n}\n\nasync function collectManualCredentials(deps: SetupDeps): Promise<WpCredentials> {\n const rawUrl = await deps.prompt('WordPress site URL: ');\n if (!rawUrl) {\n deps.error('Site URL is required.');\n deps.exit(1);\n }\n const siteUrl = normaliseSiteUrl(rawUrl);\n\n const username = await deps.prompt('WordPress username: ');\n if (!username) {\n deps.error('Username is required.');\n deps.exit(1);\n }\n\n deps.log(' Create an Application Password at:');\n deps.log(' Users → Your Profile → Application Passwords');\n deps.log('');\n\n const appPassword = await deps.promptSecret('Application Password: ');\n if (!appPassword) {\n deps.error('Application Password is required.');\n deps.exit(1);\n }\n\n return { siteUrl, username, appPassword };\n}\n\nasync function collectBrowserCredentials(deps: SetupDeps): Promise<WpCredentials> {\n const rawUrl = await deps.prompt('WordPress site URL: ');\n if (!rawUrl) {\n deps.error('Site URL is required.');\n deps.exit(1);\n }\n const siteUrl = normaliseSiteUrl(rawUrl);\n\n deps.log('');\n\n const doAuth = deps.openAuth ?? startAuthFlow;\n\n let handle: AuthFlowHandle | null = null;\n try {\n handle = await doAuth(siteUrl);\n } catch {\n // Callback server failed to start — fall through to manual auth.\n }\n\n if (handle) {\n const activeHandle = handle;\n\n deps.log(\n \"Opening your browser to authorise with WordPress. If the browser didn't open, visit:\",\n );\n deps.log('');\n deps.log(` ${activeHandle.authUrl}`);\n deps.log('');\n\n // Race: WP 7.0+ callback vs user pressing Enter to switch to manual auth.\n const manualPromise = deps.prompt('Press Enter to use the manual process, instead.\\n');\n\n const result = await Promise.race([\n activeHandle.result,\n manualPromise.then(() => {\n activeHandle.abort();\n return null;\n }),\n ]);\n\n if (result?.rejected) {\n deps.error('Authorisation was denied in the browser.');\n deps.exit(1);\n }\n\n if (result?.credentials) {\n deps.log(' Credentials received automatically.');\n return result.credentials;\n }\n }\n\n // Manual fallback: user pressed Enter, or callback server failed to start.\n // Open the non-callback auth page so WordPress shows credentials directly.\n const manualUrl = buildManualAuthUrl(siteUrl);\n const doOpen = deps.openBrowser ?? openBrowserDefault;\n await doOpen(manualUrl);\n\n deps.log(\n \"Approve the connection, then copy the credentials shown on the page. If the browser didn't open, visit:\",\n );\n deps.log(` ${manualUrl}`);\n deps.log('');\n\n const username = await deps.prompt('WordPress username (shown after approval): ');\n if (!username) {\n deps.error('Username is required.');\n deps.exit(1);\n }\n\n const appPassword = await deps.promptSecret('Application Password (shown after approval): ');\n if (!appPassword) {\n deps.error('Application Password is required.');\n deps.exit(1);\n }\n\n return { siteUrl, username, appPassword };\n}\n\n// ---------------------------------------------------------------------------\n// Credential validation\n// ---------------------------------------------------------------------------\n\nasync function validateCredentials(deps: SetupDeps, credentials: WpCredentials): Promise<void> {\n deps.log('');\n deps.log('Validating credentials...');\n\n const client = new WordPressApiClient({\n siteUrl: credentials.siteUrl,\n username: credentials.username,\n appPassword: credentials.appPassword,\n });\n\n try {\n const user = await client.validateConnection();\n const displayName = user.name ?? credentials.username;\n deps.log(` ✓ Authenticated as \"${displayName}\"`);\n } catch (err) {\n if (err instanceof WordPressApiError) {\n deps.error(err.message);\n } else {\n deps.error(`Could not connect to ${credentials.siteUrl}. Check the URL and try again.`);\n }\n deps.exit(1);\n }\n\n const wpVersion = await client.getWordPressVersion();\n deps.log(` WordPress version: ${wpVersion}`);\n\n try {\n await client.validateSyncEndpoint();\n deps.log(' ✓ Collaborative editing endpoint available');\n } catch (err) {\n if (err instanceof WordPressApiError && err.status === 404) {\n deps.log('');\n deps.error(\n 'Collaborative editing is not available.\\n' +\n ' Requires WordPress 7.0 or later, or the Gutenberg plugin 22.8 or later.\\n' +\n (wpVersion !== 'unknown' ? ` Current WordPress version: ${wpVersion}\\n` : '') +\n ' If using WordPress 7.0+, enable collaborative editing in Settings → Writing.',\n );\n deps.exit(1);\n }\n if (err instanceof WordPressApiError) {\n deps.error(err.message);\n } else {\n deps.error('Could not validate the sync endpoint.');\n }\n deps.exit(1);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client detection and selection\n// ---------------------------------------------------------------------------\n\nasync function detectAndSelectClients(\n deps: SetupDeps,\n options: SetupOptions,\n): Promise<McpClientConfig[]> {\n // Single-client mode: skip detection UI\n if (options.client) {\n const allClients = deps.detectClients?.() ?? detectInstalledClients();\n const match = allClients.find((c) => c.type === options.client);\n if (!match) {\n deps.error(`Unknown client: ${options.client}`);\n deps.exit(1);\n }\n return [match.config];\n }\n\n const clients = deps.detectClients?.() ?? detectInstalledClients();\n\n // Sort: detected first, then undetected, preserving order within each group\n const sorted = [...clients.filter((c) => c.detected), ...clients.filter((c) => !c.detected)];\n\n deps.log('');\n deps.log('Select MCP clients to configure:');\n deps.log(' (use ↑↓ to move, space to toggle, enter to confirm)');\n deps.log('');\n\n const items: CheckboxItem[] = sorted.map((c) => ({\n label: c.config.displayName,\n hint: c.detected ? undefined : '(not detected)',\n selected: c.detected,\n }));\n\n const doSelect = deps.selectCheckbox ?? checkboxPrompt;\n const result = await doSelect(items, { requireSelection: true });\n\n return result.selected.map((i) => sorted[i].config);\n}\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nasync function configureClients(\n deps: SetupDeps,\n credentials: WpCredentials,\n selectedClients: McpClientConfig[],\n): Promise<void> {\n if (selectedClients.length === 0) {\n return;\n }\n\n deps.log('');\n deps.log('Configuring MCP clients...');\n\n for (const client of selectedClients) {\n await configureSingleClient(deps, credentials, client);\n }\n}\n\nasync function configureSingleClient(\n deps: SetupDeps,\n credentials: WpCredentials,\n client: McpClientConfig,\n): Promise<void> {\n // Check if entry already exists\n const exists =\n deps.hasConfig?.(client) ??\n hasServerInConfig(client.configPath(), client.configKey, SERVER_NAME);\n if (exists) {\n const answer = await deps.prompt(\n `${client.displayName}: entry already exists. Update? (Y/n): `,\n );\n if (answer !== '' && !/^[yY]/.test(answer)) {\n deps.log(` - ${client.displayName} — skipped`);\n return;\n }\n }\n\n try {\n // If a full write override is provided (e.g., for testing), use it exclusively\n if (deps.writeConfig) {\n const result = await deps.writeConfig(client, credentials);\n if (result) {\n deps.log(` ✓ ${client.displayName} — configured via CLI`);\n } else {\n deps.log(` ✗ ${client.displayName} — configuration returned false`);\n }\n return;\n }\n\n // Try CLI first if available\n if (client.useCli) {\n const cliResult = await client.useCli(credentials);\n if (cliResult) {\n deps.log(` ✓ ${client.displayName} — configured via CLI`);\n return;\n }\n }\n\n // Fall back to config file writing\n addServerToConfig(\n client.configPath(),\n client.configKey,\n SERVER_NAME,\n buildServerEntry(credentials),\n );\n deps.log(` ✓ ${client.displayName} — written to ${client.configPath()}`);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n deps.log(` ✗ ${client.displayName} — failed: ${message}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Remove flow\n// ---------------------------------------------------------------------------\n\nasync function runRemove(deps: SetupDeps): Promise<void> {\n deps.log('');\n deps.log('claudaborative-editing remove');\n deps.log('=============================');\n deps.log('');\n\n const clients = deps.detectClients?.() ?? detectInstalledClients();\n\n // Find which clients have our entry\n const configured = clients.filter((c) => {\n try {\n return (\n deps.hasConfig?.(c.config) ??\n hasServerInConfig(c.config.configPath(), c.config.configKey, SERVER_NAME)\n );\n } catch {\n // Corrupt or unreadable config file — treat as not configured\n return false;\n }\n });\n\n if (configured.length === 0) {\n deps.log('No MCP clients have claudaborative-editing configured.');\n deps.cleanup();\n return;\n }\n\n deps.log('Select clients to remove from:');\n deps.log(' (use ↑↓ to move, space to toggle, enter to confirm)');\n deps.log('');\n\n const removeItems: CheckboxItem[] = configured.map((c) => ({\n label: c.config.displayName,\n selected: true,\n }));\n\n const doSelect = deps.selectCheckbox ?? checkboxPrompt;\n const removeResult = await doSelect(removeItems, { requireSelection: true });\n\n const selected = removeResult.selected.map((i) => configured[i]);\n\n deps.log('');\n for (const entry of selected) {\n await removeSingleClient(deps, entry.config);\n }\n\n deps.log('');\n deps.log('Done! Restart your MCP clients to complete removal.');\n deps.cleanup();\n}\n\nasync function removeSingleClient(deps: SetupDeps, client: McpClientConfig): Promise<void> {\n try {\n // If a full remove override is provided (e.g., for testing), use it exclusively\n if (deps.removeConfig) {\n const result = await deps.removeConfig(client);\n if (result) {\n deps.log(` ✓ ${client.displayName} — removed via CLI`);\n } else {\n deps.log(` - ${client.displayName} — removal returned false`);\n }\n return;\n }\n\n // Try CLI removal first\n if (client.removeCli) {\n const cliResult = await client.removeCli();\n if (cliResult) {\n deps.log(` ✓ ${client.displayName} — removed via CLI`);\n return;\n }\n }\n\n // Fall back to config file removal\n const removed = removeServerFromConfig(client.configPath(), client.configKey, SERVER_NAME);\n if (removed) {\n deps.log(` ✓ ${client.displayName} — removed from ${client.configPath()}`);\n } else {\n deps.log(` - ${client.displayName} — entry not found`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n deps.log(` ✗ ${client.displayName} — failed: ${message}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// URL normalisation\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure a site URL has a scheme and no trailing slashes.\n * If the user enters a bare domain like \"pento.net\", prepend \"https://\".\n */\nfunction normaliseSiteUrl(url: string): string {\n let normalised = url;\n if (!/^https?:\\/\\//i.test(normalised)) {\n normalised = `https://${normalised}`;\n }\n return normalised.replace(/\\/+$/, '');\n}\n","import { VERSION } from './server.js';\nimport type { McpClientType, SetupOptions } from './cli/types.js';\n\nconst args = process.argv.slice(2);\n\nif (args.includes('--version') || args.includes('-v')) {\n console.log(VERSION);\n process.exit(0);\n}\n\nif (args.includes('--help') || args.includes('-h')) {\n console.log(`claudaborative-editing v${VERSION}\n\nMCP server for collaborative WordPress post editing via Yjs CRDT.\n\nUsage:\n claudaborative-editing Start the MCP server (stdio transport)\n claudaborative-editing setup Interactive setup wizard\n claudaborative-editing setup --manual Use manual credential entry\n claudaborative-editing setup --remove Remove configuration from MCP clients\n claudaborative-editing setup --client <name> Configure a specific client only\n claudaborative-editing --version Print version\n claudaborative-editing --help Show this help\n\nEnvironment variables:\n WP_SITE_URL WordPress site URL\n WP_USERNAME WordPress username\n WP_APP_PASSWORD WordPress Application Password\n\nMore info: https://github.com/pento/claudaborative-editing`);\n process.exit(0);\n}\n\nif (args[0] === 'setup') {\n const { runSetup } = await import('./cli/setup.js');\n const options: SetupOptions = {};\n if (args.includes('--manual')) {\n options.manual = true;\n }\n if (args.includes('--remove')) {\n options.remove = true;\n }\n const clientIdx = args.indexOf('--client');\n if (clientIdx !== -1) {\n if (args[clientIdx + 1]) {\n options.client = args[clientIdx + 1] as McpClientType;\n } else {\n console.error('Error: --client requires a client name. See --help for usage.');\n process.exit(1);\n }\n }\n await runSetup(undefined, options);\n} else {\n const { startServer } = await import('./server.js');\n startServer().catch((error: unknown) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":["Y","init_types","Y","Y","init_types","z","z","z","z","z","z","z","z","z","platform","args","existsSync","dirname","runSetup","startServer"]}
|