[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F22WRMHEV5RYP6B0SS0Z42":3,"skill-same:01M6F22WRMHEV5RYP6B0SS0Z42":96},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":62,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":64,"updatedAt":65,"install":66,"resources":79},"01M6F22WRMHEV5RYP6B0SS0Z42","x-article-publisher",null,"Publish Markdown articles to X (Twitter) Articles editor with proper formatting. Use when user wants to publish a Markdown file\u002FURL to X Articles, or mentions \"publish to X\", \"post article to Twitter\", \"X article\", or wants help with X Premium article publishing. Handles cover image upload and converts Markdown to rich text automatically.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"x article publisher","article","publisher","publishing","URL","with","post","formatting","upload","x articles","image","use","user","twitter","text","markdown","publish","file","help","editor","2026-11-10 10:12:30",false,"---\nname: x-article-publisher\ndescription: Publish Markdown articles to X (Twitter) Articles editor with proper formatting. Use when user wants to publish a Markdown file\u002FURL to X Articles, or mentions \"publish to X\", \"post article to Twitter\", \"X article\", or wants help with X Premium article publishing. Handles cover image upload and converts Markdown to rich text automatically.\n---\n\n# X Article Publisher\n\nPublish Markdown content to X (Twitter) Articles editor, preserving formatting with rich text conversion.\n\n## Prerequisites\n\n- Playwright MCP for browser automation\n- User logged into X with Premium Plus subscription\n- Python 3.9+ with dependencies: `pip install Pillow pyobjc-framework-Cocoa`\n\n## Scripts\n\nLocated in `~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002F`:\n\n### parse_markdown.py\nParse Markdown and extract structured data:\n```bash\npython parse_markdown.py \u003Cmarkdown_file> [--output json|html] [--html-only]\n```\nReturns JSON with: title, cover_image, content_images (with block_index for positioning), html, total_blocks\n\n### copy_to_clipboard.py\nCopy image or HTML to system clipboard:\n```bash\n# Copy image (with optional compression)\npython copy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimage.jpg [--quality 80]\n\n# Copy HTML for rich text paste\npython copy_to_clipboard.py html --file \u002Fpath\u002Fto\u002Fcontent.html\n```\n\n## Workflow\n\n**Strategy: \"先文后图\" (Text First, Images Later)**\n\nFor articles with multiple images, paste ALL text content first, then insert images at correct positions using block index.\n\n1. Parse Markdown with Python script → get title, images with block_index, HTML\n2. Navigate to X Articles editor\n3. Upload cover image (first image)\n4. Fill title\n5. Copy HTML to clipboard (Python) → Paste with Cmd+V\n6. Insert content images at positions specified by block_index\n7. Save as draft (NEVER auto-publish)\n\n## 高效执行原则 (Efficiency Guidelines)\n\n**目标**: 最小化操作之间的等待时间，实现流畅的自动化体验。\n\n### 1. 避免不必要的 browser_snapshot\n\n大多数浏览器操作（click, type, press_key 等）都会在返回结果中包含页面状态。**不要**在每次操作后单独调用 `browser_snapshot`，直接使用操作返回的页面状态即可。\n\n```\n❌ 错误做法：\nbrowser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...\n\n✅ 正确做法：\nbrowser_click → 从返回结果中获取页面状态 → browser_click → ...\n```\n\n### 2. 避免不必要的 browser_wait_for\n\n只在以下情况使用 `browser_wait_for`：\n- 等待图片上传完成（`textGone=\"正在上传媒体\"`）\n- 等待页面初始加载（极少数情况）\n\n**不要**使用 `browser_wait_for` 来等待按钮或输入框出现 - 它们在页面加载完成后立即可用。\n\n### 3. 并行执行独立操作\n\n当两个操作没有依赖关系时，可以在同一个消息中并行调用多个工具：\n\n```\n✅ 可以并行：\n- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)\n- 解析Markdown生成JSON + 生成HTML文件\n\n❌ 不能并行（有依赖）：\n- 必须先点击create才能上传封面图\n- 必须先粘贴内容才能插入图片\n```\n\n### 4. 连续执行浏览器操作\n\n每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作：\n\n```\n# 理想流程（每步直接执行，不额外等待）：\nbrowser_navigate → 从返回状态找create按钮 → browser_click(create)\n→ 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload\n→ 从返回状态找应用按钮 → browser_click(应用)\n→ 从返回状态找标题框 → browser_type(标题)\n→ 点击编辑器 → browser_press_key(Meta+v)\n→ ...\n```\n\n### 5. 准备工作前置\n\n在开始浏览器操作之前，先完成所有准备工作：\n1. 解析 Markdown 获取 JSON 数据\n2. 生成 HTML 文件到 \u002Ftmp\u002F\n3. 记录 title、cover_image、content_images 等信息\n\n这样浏览器操作阶段可以连续执行，不需要中途停下来处理数据。\n\n## Step 1: Parse Markdown (Python)\n\nUse `parse_markdown.py` to extract all structured data:\n\n```bash\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md\n```\n\nOutput JSON:\n```json\n{\n  \"title\": \"Article Title\",\n  \"cover_image\": \"\u002Fpath\u002Fto\u002Ffirst-image.jpg\",\n  \"content_images\": [\n    {\"path\": \"\u002Fpath\u002Fto\u002Fimg2.jpg\", \"block_index\": 5, \"after_text\": \"context for debugging...\"},\n    {\"path\": \"\u002Fpath\u002Fto\u002Fimg3.jpg\", \"block_index\": 12, \"after_text\": \"another context...\"}\n  ],\n  \"html\": \"\u003Cp>Content...\u003C\u002Fp>\u003Ch2>Section\u003C\u002Fh2>...\",\n  \"total_blocks\": 45\n}\n```\n\n**Key fields:**\n- `block_index`: The image should be inserted AFTER block element at this index (0-indexed)\n- `total_blocks`: Total number of block elements in the HTML\n- `after_text`: Kept for reference\u002Fdebugging only, NOT for positioning\n\nSave HTML to temp file for clipboard:\n```bash\npython parse_markdown.py article.md --html-only > \u002Ftmp\u002Farticle_html.html\n```\n\n## Step 2: Open X Articles Editor\n\n```\nbrowser_navigate: https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n```\n\n**重要**: 页面加载后会显示草稿列表，不是编辑器。需要：\n\n1. **等待页面加载完成**: 使用 `browser_snapshot` 检查页面状态\n2. **立即点击 \"create\" 按钮**: 不要等待 \"添加标题\" 等编辑器元素，它们只有点击 create 后才出现\n3. **等待编辑器加载**: 点击 create 后，等待编辑器元素出现\n\n```\n# 1. 导航到页面\nbrowser_navigate: https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n\n# 2. 获取页面快照，找到 create 按钮\nbrowser_snapshot\n\n# 3. 点击 create 按钮（通常 ref 类似 \"create\" 或带有 create 标签）\nbrowser_click: element=\"create button\", ref=\u003Ccreate_button_ref>\n\n# 4. 现在编辑器应该打开了，可以继续上传封面图等操作\n```\n\n**注意**: 不要使用 `browser_wait_for text=\"添加标题\"` 来等待页面加载，因为这个文本只有在点击 create 后才出现，会导致超时。\n\nIf login needed, prompt user to log in manually.\n\n## Step 3: Upload Cover Image\n\n1. Click \"添加照片或视频\" button\n2. Use browser_file_upload with the cover image path (from JSON output)\n3. Verify image uploaded\n\n## Step 4: Fill Title\n\n- Find textbox with \"添加标题\" placeholder\n- Use browser_type to input title (from JSON output)\n\n## Step 5: Paste Text Content (Python Clipboard)\n\nCopy HTML to system clipboard using Python, then paste:\n\n```bash\n# Copy HTML to clipboard\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py html --file \u002Ftmp\u002Farticle_html.html\n```\n\nThen in browser:\n```\nbrowser_click on editor textbox\nbrowser_press_key: Meta+v\n```\n\nThis preserves all rich text formatting (H2, bold, links, lists).\n\n## Step 6: Insert Content Images (Block Index Positioning)\n\n**关键改进**: 使用 `block_index` 精确定位，而非依赖文字匹配。\n\n### 定位原理\n\n粘贴 HTML 后，编辑器中的内容结构为一系列块元素（段落、标题、引用等）。每张图片的 `block_index` 表示它应该插入在第 N 个块元素之后。\n\n### 操作步骤\n\n1. **获取所有块元素**: 使用 browser_snapshot 获取编辑器内容，找到 textbox 下的所有子元素\n2. **按索引定位**: 根据 `block_index` 点击对应的块元素\n3. **粘贴图片**: 复制图片到剪贴板后粘贴\n\nFor each content image (from `content_images` array):\n\n```bash\n# 1. Copy image to clipboard (with compression)\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimg.jpg --quality 85\n```\n\n```\n# 2. Click the block element at block_index\n# Example: if block_index=5, click the 6th block element (0-indexed)\nbrowser_click on the element at position block_index in the editor\n\n# 3. Paste image\nbrowser_press_key: Meta+v\n\n# 4. Wait for upload (use short time, returns immediately when done)\nbrowser_wait_for textGone=\"正在上传媒体\" time=2\n```\n\n### 定位策略\n\n在 browser_snapshot 返回的结构中，编辑器内容通常是：\n```yaml\ntextbox [ref=xxx]:\n  generic [ref=block0]:  # block_index 0\n    - paragraph content\n  heading [ref=block1]:   # block_index 1\n    - h2 content\n  generic [ref=block2]:  # block_index 2\n    - paragraph content\n  ...\n```\n\n要在 `block_index=5` 后插入图片：\n1. 找到编辑器 textbox 下的第 6 个子元素（索引从0开始）\n2. 点击该元素\n3. 粘贴图片\n\n**注意**: 每插入一张图片后，后续图片的实际位置会偏移。建议按 `block_index` **从大到小**的顺序插入图片，这样先插入的图片不会影响后续图片的索引。\n\n### 反向插入示例\n\n如果有3张图片，block_index 分别为 5, 12, 27：\n1. 先插入 block_index=27 的图片\n2. 再插入 block_index=12 的图片\n3. 最后插入 block_index=5 的图片\n\n这样每次插入都不会影响前面已经定位好的位置。\n\n## Step 7: Save Draft\n\n1. Verify content pasted (check word count indicator)\n2. Draft auto-saves, or click Save button if needed\n3. Click \"预览\" to verify formatting\n4. Report: \"Draft saved. Review and publish manually.\"\n\n## Critical Rules\n\n1. **NEVER publish** - Only save draft\n2. **First image = cover** - Upload first image as cover image\n3. **Rich text conversion** - Always convert Markdown to HTML before pasting\n4. **Use clipboard API** - Paste via clipboard for proper formatting\n5. **Block index positioning** - Use block_index for precise image placement\n6. **Reverse order insertion** - Insert images from highest to lowest block_index\n7. **H1 title handling** - H1 is used as title only, not included in body\n\n## Supported Formatting\n\n- H2 headers (## )\n- Blockquotes (> )\n- Code blocks (``` ... ```) - converted to blockquotes since X doesn't support `\u003Cpre>\u003Ccode>`\n- Bold text (**)\n- Hyperlinks ([text](url))\n- Ordered lists (1. 2. 3.)\n- Unordered lists (- )\n- Paragraphs\n\n## Example Flow\n\nUser: \"Publish \u002Fpath\u002Fto\u002Farticle.md to X\"\n\n```bash\n# Step 1: Parse Markdown\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md > \u002Ftmp\u002Farticle.json\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md --html-only > \u002Ftmp\u002Farticle_html.html\n```\n\n2. Navigate to https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n3. Upload cover image (browser_file_upload for cover only)\n4. Fill title (from JSON: `title`)\n5. Copy & paste HTML:\n   ```bash\n   python ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py html --file \u002Ftmp\u002Farticle_html.html\n   ```\n   Then: browser_press_key Meta+v\n6. For each content image, **in reverse order of block_index**:\n   ```bash\n   python copy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimg.jpg --quality 85\n   ```\n   - Click block element at `block_index` position\n   - browser_press_key Meta+v\n   - Wait until upload complete\n7. Verify in preview\n8. \"Draft saved. Please review and publish manually.\"\n\n## Best Practices\n\n### 为什么用 block_index 而非文字匹配？\n\n1. **精确定位**: 不依赖文字内容，即使多处文字相似也能正确定位\n2. **可靠性**: 索引是确定性的，不会因为文字相似而混淆\n3. **调试方便**: `after_text` 仍保留用于人工核验\n\n### 为什么用 Python 而非浏览器内 JavaScript？\n\n1. **本地处理更可靠**: Python 直接操作系统剪贴板，不受浏览器沙盒限制\n2. **图片压缩**: 上传前压缩图片 (--quality 85)，减少上传时间\n3. **代码复用**: 脚本固定不变，无需每次重新编写转换逻辑\n4. **调试方便**: 脚本可单独测试，问题易定位\n\n### 等待策略\n\n**关键理解**: `browser_wait_for` 的 `textGone` 参数会在文字消失时**立即返回**，`time` 只是最大等待时间，不是固定等待时间。\n\n- ❌ 保守等待: `time=5` 或 `time=10`，如果上传只需2秒，剩余时间全浪费\n- ✅ 短间隔轮询: `time=2`，条件满足立即返回，最多等2秒\n\n```\n# 正确用法：短 time 值，条件满足立即返回\nbrowser_wait_for textGone=\"正在上传媒体\" time=2\n\n# 错误用法：固定长时间等待\nbrowser_wait_for time=5  # 无条件等待5秒，浪费时间\n```\n\n**原则**: 不要预设\"需要等多久\"，而是设置一个合理的最大值，让条件检测尽快返回。\n\n### 图片插入效率\n\n每张图片的浏览器操作从5步减少到2步：\n- 旧: 点击 → 添加媒体 → 媒体 → 添加照片 → file_upload\n- 新: 点击段落 → Meta+v\n\n### 封面图 vs 内容图\n\n- **封面图**: 使用 browser_file_upload（因为有专门的上传按钮）\n- **内容图**: 使用 Python 剪贴板 + 粘贴（更高效）\n","# X Article Publisher\n\nPublish Markdown content to X (Twitter) Articles editor, preserving formatting with rich text conversion.\n\n## Prerequisites\n\n- Playwright MCP for browser automation\n- User logged into X with Premium Plus subscription\n- Python 3.9+ with dependencies: `pip install Pillow pyobjc-framework-Cocoa`\n\n## Scripts\n\nLocated in `~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002F`:\n\n### parse_markdown.py\nParse Markdown and extract structured data:\n```bash\npython parse_markdown.py \u003Cmarkdown_file> [--output json|html] [--html-only]\n```\nReturns JSON with: title, cover_image, content_images (with block_index for positioning), html, total_blocks\n\n### copy_to_clipboard.py\nCopy image or HTML to system clipboard:\n```bash\n# Copy image (with optional compression)\npython copy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimage.jpg [--quality 80]\n\n# Copy HTML for rich text paste\npython copy_to_clipboard.py html --file \u002Fpath\u002Fto\u002Fcontent.html\n```\n\n## Workflow\n\n**Strategy: \"先文后图\" (Text First, Images Later)**\n\nFor articles with multiple images, paste ALL text content first, then insert images at correct positions using block index.\n\n1. Parse Markdown with Python script → get title, images with block_index, HTML\n2. Navigate to X Articles editor\n3. Upload cover image (first image)\n4. Fill title\n5. Copy HTML to clipboard (Python) → Paste with Cmd+V\n6. Insert content images at positions specified by block_index\n7. Save as draft (NEVER auto-publish)\n\n## 高效执行原则 (Efficiency Guidelines)\n\n**目标**: 最小化操作之间的等待时间，实现流畅的自动化体验。\n\n### 1. 避免不必要的 browser_snapshot\n\n大多数浏览器操作（click, type, press_key 等）都会在返回结果中包含页面状态。**不要**在每次操作后单独调用 `browser_snapshot`，直接使用操作返回的页面状态即可。\n\n```\n❌ 错误做法：\nbrowser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...\n\n✅ 正确做法：\nbrowser_click → 从返回结果中获取页面状态 → browser_click → ...\n```\n\n### 2. 避免不必要的 browser_wait_for\n\n只在以下情况使用 `browser_wait_for`：\n- 等待图片上传完成（`textGone=\"正在上传媒体\"`）\n- 等待页面初始加载（极少数情况）\n\n**不要**使用 `browser_wait_for` 来等待按钮或输入框出现 - 它们在页面加载完成后立即可用。\n\n### 3. 并行执行独立操作\n\n当两个操作没有依赖关系时，可以在同一个消息中并行调用多个工具：\n\n```\n✅ 可以并行：\n- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)\n- 解析Markdown生成JSON + 生成HTML文件\n\n❌ 不能并行（有依赖）：\n- 必须先点击create才能上传封面图\n- 必须先粘贴内容才能插入图片\n```\n\n### 4. 连续执行浏览器操作\n\n每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作：\n\n```\n# 理想流程（每步直接执行，不额外等待）：\nbrowser_navigate → 从返回状态找create按钮 → browser_click(create)\n→ 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload\n→ 从返回状态找应用按钮 → browser_click(应用)\n→ 从返回状态找标题框 → browser_type(标题)\n→ 点击编辑器 → browser_press_key(Meta+v)\n→ ...\n```\n\n### 5. 准备工作前置\n\n在开始浏览器操作之前，先完成所有准备工作：\n1. 解析 Markdown 获取 JSON 数据\n2. 生成 HTML 文件到 \u002Ftmp\u002F\n3. 记录 title、cover_image、content_images 等信息\n\n这样浏览器操作阶段可以连续执行，不需要中途停下来处理数据。\n\n## Step 1: Parse Markdown (Python)\n\nUse `parse_markdown.py` to extract all structured data:\n\n```bash\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md\n```\n\nOutput JSON:\n```json\n{\n  \"title\": \"Article Title\",\n  \"cover_image\": \"\u002Fpath\u002Fto\u002Ffirst-image.jpg\",\n  \"content_images\": [\n    {\"path\": \"\u002Fpath\u002Fto\u002Fimg2.jpg\", \"block_index\": 5, \"after_text\": \"context for debugging...\"},\n    {\"path\": \"\u002Fpath\u002Fto\u002Fimg3.jpg\", \"block_index\": 12, \"after_text\": \"another context...\"}\n  ],\n  \"html\": \"\u003Cp>Content...\u003C\u002Fp>\u003Ch2>Section\u003C\u002Fh2>...\",\n  \"total_blocks\": 45\n}\n```\n\n**Key fields:**\n- `block_index`: The image should be inserted AFTER block element at this index (0-indexed)\n- `total_blocks`: Total number of block elements in the HTML\n- `after_text`: Kept for reference\u002Fdebugging only, NOT for positioning\n\nSave HTML to temp file for clipboard:\n```bash\npython parse_markdown.py article.md --html-only > \u002Ftmp\u002Farticle_html.html\n```\n\n## Step 2: Open X Articles Editor\n\n```\nbrowser_navigate: https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n```\n\n**重要**: 页面加载后会显示草稿列表，不是编辑器。需要：\n\n1. **等待页面加载完成**: 使用 `browser_snapshot` 检查页面状态\n2. **立即点击 \"create\" 按钮**: 不要等待 \"添加标题\" 等编辑器元素，它们只有点击 create 后才出现\n3. **等待编辑器加载**: 点击 create 后，等待编辑器元素出现\n\n```\n# 1. 导航到页面\nbrowser_navigate: https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n\n# 2. 获取页面快照，找到 create 按钮\nbrowser_snapshot\n\n# 3. 点击 create 按钮（通常 ref 类似 \"create\" 或带有 create 标签）\nbrowser_click: element=\"create button\", ref=\u003Ccreate_button_ref>\n\n# 4. 现在编辑器应该打开了，可以继续上传封面图等操作\n```\n\n**注意**: 不要使用 `browser_wait_for text=\"添加标题\"` 来等待页面加载，因为这个文本只有在点击 create 后才出现，会导致超时。\n\nIf login needed, prompt user to log in manually.\n\n## Step 3: Upload Cover Image\n\n1. Click \"添加照片或视频\" button\n2. Use browser_file_upload with the cover image path (from JSON output)\n3. Verify image uploaded\n\n## Step 4: Fill Title\n\n- Find textbox with \"添加标题\" placeholder\n- Use browser_type to input title (from JSON output)\n\n## Step 5: Paste Text Content (Python Clipboard)\n\nCopy HTML to system clipboard using Python, then paste:\n\n```bash\n# Copy HTML to clipboard\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py html --file \u002Ftmp\u002Farticle_html.html\n```\n\nThen in browser:\n```\nbrowser_click on editor textbox\nbrowser_press_key: Meta+v\n```\n\nThis preserves all rich text formatting (H2, bold, links, lists).\n\n## Step 6: Insert Content Images (Block Index Positioning)\n\n**关键改进**: 使用 `block_index` 精确定位，而非依赖文字匹配。\n\n### 定位原理\n\n粘贴 HTML 后，编辑器中的内容结构为一系列块元素（段落、标题、引用等）。每张图片的 `block_index` 表示它应该插入在第 N 个块元素之后。\n\n### 操作步骤\n\n1. **获取所有块元素**: 使用 browser_snapshot 获取编辑器内容，找到 textbox 下的所有子元素\n2. **按索引定位**: 根据 `block_index` 点击对应的块元素\n3. **粘贴图片**: 复制图片到剪贴板后粘贴\n\nFor each content image (from `content_images` array):\n\n```bash\n# 1. Copy image to clipboard (with compression)\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimg.jpg --quality 85\n```\n\n```\n# 2. Click the block element at block_index\n# Example: if block_index=5, click the 6th block element (0-indexed)\nbrowser_click on the element at position block_index in the editor\n\n# 3. Paste image\nbrowser_press_key: Meta+v\n\n# 4. Wait for upload (use short time, returns immediately when done)\nbrowser_wait_for textGone=\"正在上传媒体\" time=2\n```\n\n### 定位策略\n\n在 browser_snapshot 返回的结构中，编辑器内容通常是：\n```yaml\ntextbox [ref=xxx]:\n  generic [ref=block0]:  # block_index 0\n    - paragraph content\n  heading [ref=block1]:   # block_index 1\n    - h2 content\n  generic [ref=block2]:  # block_index 2\n    - paragraph content\n  ...\n```\n\n要在 `block_index=5` 后插入图片：\n1. 找到编辑器 textbox 下的第 6 个子元素（索引从0开始）\n2. 点击该元素\n3. 粘贴图片\n\n**注意**: 每插入一张图片后，后续图片的实际位置会偏移。建议按 `block_index` **从大到小**的顺序插入图片，这样先插入的图片不会影响后续图片的索引。\n\n### 反向插入示例\n\n如果有3张图片，block_index 分别为 5, 12, 27：\n1. 先插入 block_index=27 的图片\n2. 再插入 block_index=12 的图片\n3. 最后插入 block_index=5 的图片\n\n这样每次插入都不会影响前面已经定位好的位置。\n\n## Step 7: Save Draft\n\n1. Verify content pasted (check word count indicator)\n2. Draft auto-saves, or click Save button if needed\n3. Click \"预览\" to verify formatting\n4. Report: \"Draft saved. Review and publish manually.\"\n\n## Critical Rules\n\n1. **NEVER publish** - Only save draft\n2. **First image = cover** - Upload first image as cover image\n3. **Rich text conversion** - Always convert Markdown to HTML before pasting\n4. **Use clipboard API** - Paste via clipboard for proper formatting\n5. **Block index positioning** - Use block_index for precise image placement\n6. **Reverse order insertion** - Insert images from highest to lowest block_index\n7. **H1 title handling** - H1 is used as title only, not included in body\n\n## Supported Formatting\n\n- H2 headers (## )\n- Blockquotes (> )\n- Code blocks (``` ... ```) - converted to blockquotes since X doesn't support `\u003Cpre>\u003Ccode>`\n- Bold text (**)\n- Hyperlinks ([text](url))\n- Ordered lists (1. 2. 3.)\n- Unordered lists (- )\n- Paragraphs\n\n## Example Flow\n\nUser: \"Publish \u002Fpath\u002Fto\u002Farticle.md to X\"\n\n```bash\n# Step 1: Parse Markdown\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md > \u002Ftmp\u002Farticle.json\npython ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py \u002Fpath\u002Fto\u002Farticle.md --html-only > \u002Ftmp\u002Farticle_html.html\n```\n\n2. Navigate to https:\u002F\u002Fx.com\u002Fcompose\u002Farticles\n3. Upload cover image (browser_file_upload for cover only)\n4. Fill title (from JSON: `title`)\n5. Copy & paste HTML:\n   ```bash\n   python ~\u002F.claude\u002Fskills\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py html --file \u002Ftmp\u002Farticle_html.html\n   ```\n   Then: browser_press_key Meta+v\n6. For each content image, **in reverse order of block_index**:\n   ```bash\n   python copy_to_clipboard.py image \u002Fpath\u002Fto\u002Fimg.jpg --quality 85\n   ```\n   - Click block element at `block_index` position\n   - browser_press_key Meta+v\n   - Wait until upload complete\n7. Verify in preview\n8. \"Draft saved. Please review and publish manually.\"\n\n## Best Practices\n\n### 为什么用 block_index 而非文字匹配？\n\n1. **精确定位**: 不依赖文字内容，即使多处文字相似也能正确定位\n2. **可靠性**: 索引是确定性的，不会因为文字相似而混淆\n3. **调试方便**: `after_text` 仍保留用于人工核验\n\n### 为什么用 Python 而非浏览器内 JavaScript？\n\n1. **本地处理更可靠**: Python 直接操作系统剪贴板，不受浏览器沙盒限制\n2. **图片压缩**: 上传前压缩图片 (--quality 85)，减少上传时间\n3. **代码复用**: 脚本固定不变，无需每次重新编写转换逻辑\n4. **调试方便**: 脚本可单独测试，问题易定位\n\n### 等待策略\n\n**关键理解**: `browser_wait_for` 的 `textGone` 参数会在文字消失时**立即返回**，`time` 只是最大等待时间，不是固定等待时间。\n\n- ❌ 保守等待: `time=5` 或 `time=10`，如果上传只需2秒，剩余时间全浪费\n- ✅ 短间隔轮询: `time=2`，条件满足立即返回，最多等2秒\n\n```\n# 正确用法：短 time 值，条件满足立即返回\nbrowser_wait_for textGone=\"正在上传媒体\" time=2\n\n# 错误用法：固定长时间等待\nbrowser_wait_for time=5  # 无条件等待5秒，浪费时间\n```\n\n**原则**: 不要预设\"需要等多久\"，而是设置一个合理的最大值，让条件检测尽快返回。\n\n### 图片插入效率\n\n每张图片的浏览器操作从5步减少到2步：\n- 旧: 点击 → 添加媒体 → 媒体 → 添加照片 → file_upload\n- 新: 点击段落 → Meta+v\n\n### 封面图 vs 内容图\n\n- **封面图**: 使用 browser_file_upload（因为有专门的上传按钮）\n- **内容图**: 使用 Python 剪贴板 + 粘贴（更高效）\n",{"name":5,"description":7},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":67,"prompt":77,"zipAvailable":78},[68,71,74],{"tool":69,"command":70},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill x-article-publisher",{"tool":72,"command":73},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill x-article-publisher",{"tool":75,"command":76},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill x-article-publisher","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher\u002FSKILL.md",true,[80,86,90],{"path":81,"resourceType":82,"resourceTypeDesc":83,"sizeBytes":84,"sourceHtmlUrl":85},"scripts\u002Fcopy_to_clipboard.py","SCRIPT","脚本",6185,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher\u002Fscripts\u002Fcopy_to_clipboard.py",{"path":87,"resourceType":82,"resourceTypeDesc":83,"sizeBytes":88,"sourceHtmlUrl":89},"scripts\u002Fparse_markdown.py",10217,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher\u002Fscripts\u002Fparse_markdown.py",{"path":91,"resourceType":92,"resourceTypeDesc":93,"sizeBytes":94,"sourceHtmlUrl":95},"skill-report.json","REFERENCE","参考文档",11446,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fzhanlincui\u002Fx-article-publisher\u002Fskill-report.json",[97,109,119,128,134,141],{"skillNo":98,"name":99,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":105,"publishedAt":52},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[102],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[106,107,108],"model","model hierarchy","model hierarchy skill",{"skillNo":110,"name":111,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":115,"publishedAt":52},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[114],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},[116,117,118],"MCP","zoom","zoom mcp",{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":52},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[125,126,127,117],"sdk","zoom apps sdk","apps",{"skillNo":129,"name":130,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":133,"publishedAt":52},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[130],{"skillNo":135,"name":136,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":140,"publishedAt":52},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[139],{"categoryNo":103,"categoryName":104,"taxonomyType":21,"taxonomyTypeDesc":22},[136],{"skillNo":142,"name":143,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":146,"publishedAt":52},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[143]]