publish-x-article

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Publish X Article

发布X文章

Publish Markdown content to X (Twitter) Articles editor, preserving formatting with rich text conversion. Automatically handles X Premium limitations by converting unsupported elements to images.
将Markdown内容发布到X(Twitter)Articles编辑器,通过富文本转换保留格式。自动处理X Premium的限制,将不支持的元素转换为图片。

Credits

致谢

This skill is inspired by and based on wshuyi/x-article-publisher-skill. Thank you to the original author for the foundational work.
本技能受wshuyi/x-article-publisher-skill启发并基于其开发。感谢原作者的奠基性工作。

Interactive Setup: Ask Subscription Type

交互式设置:询问订阅类型

IMPORTANT: Before processing the article, ask the user about their X subscription type if not already known.
重要:在处理文章之前,如果尚未知晓用户的X订阅类型,请先询问用户。

Prompt the User

提示用户

Before publishing, I need to know your X subscription type to handle formatting correctly:

1. **X Premium** - Basic tier ($8/month)
2. **X Premium+** - Plus tier ($16/month)

Which subscription do you have? (Premium / Premium+)
For Chinese users:
在发布之前,我需要了解您的 X 订阅类型以正确处理格式:

1. **X Premium** - 基础版 ($8/月)
2. **X Premium+** - 高级版 ($16/月)

您使用的是哪个版本?(Premium / Premium+)
Before publishing, I need to know your X subscription type to handle formatting correctly:

1. **X Premium** - Basic tier ($8/month)
2. **X Premium+** - Plus tier ($16/month)

Which subscription do you have? (Premium / Premium+)
针对中文用户:
在发布之前,我需要了解您的X订阅类型以正确处理格式:

1. **X Premium** - 基础版 ($8/月)
2. **X Premium+** - 高级版 ($16/月)

您使用的是哪个版本?(Premium / Premium+)

Remember the Answer

记住用户的回答

Once the user answers, remember their subscription type for the rest of the session. Don't ask again unless they explicitly want to change it.
一旦用户给出回答,在本次会话的剩余时间内记住其订阅类型。除非用户明确要求更改,否则不要再询问。

X Subscription Feature Comparison

X订阅功能对比

FeatureX PremiumX Premium+
H1 headers (
#
)
Title onlyTitle only
H2 headers (
##
)
YesYes
H3+ headers (
###
, etc.)
NoYes
Markdown tablesNoYes
Mermaid diagramsNoNo (not supported by X)
Code blocksBlockquotesBlockquotes
Bold, italic, linksYesYes
ListsYesYes
BlockquotesYesYes
ImagesYesYes
功能X PremiumX Premium+
H1标题 (
#
)
仅用作标题仅用作标题
H2标题 (
##
)
支持支持
H3及以上标题 (
###
等)
不支持支持
Markdown表格不支持支持
Mermaid图表不支持不支持(X本身不支持)
代码块转换为块引用转换为块引用
粗体、斜体、链接支持支持
列表支持支持
块引用支持支持
图片支持支持

Pre-Processing Required by Subscription

按订阅类型进行预处理

X Premium (Basic):
  • Convert H3+ headers → H2 or bold
  • Convert tables → PNG images
  • Convert mermaid → PNG images
X Premium+ (Plus):
  • Keep H3+ headers as-is
  • Keep tables as-is (rendered natively)
  • Convert mermaid → PNG images (still not supported)
X Premium(基础版):
  • 将H3及以上标题转换为H2或粗体文本
  • 将表格转换为PNG图片
  • 将Mermaid图表转换为PNG图片
X Premium+(高级版):
  • 保留H3及以上标题原样
  • 保留表格原样(原生渲染)
  • 将Mermaid图表转换为PNG图片(仍不支持)

Prerequisites

前置条件

  • Playwright MCP for browser automation
  • User logged into X with Premium subscription
  • Python 3.9+ with dependencies:
    • macOS:
      pip install Pillow pyobjc-framework-Cocoa markdown
    • Windows:
      pip install Pillow pywin32 clip-util markdown
  • For Mermaid diagrams:
    npm install -g @mermaid-js/mermaid-cli
  • 用于浏览器自动化的Playwright MCP
  • 用户已登录X且拥有Premium订阅
  • Python 3.9及以上版本,并安装以下依赖:
    • macOS:
      pip install Pillow pyobjc-framework-Cocoa markdown
    • Windows:
      pip install Pillow pywin32 clip-util markdown
  • 处理Mermaid图表需安装:
    npm install -g @mermaid-js/mermaid-cli

Scripts

脚本位置

Located in
~/.claude/skills/publish-x-article/scripts/
:
位于
~/.claude/skills/publish-x-article/scripts/

parse_markdown.py

parse_markdown.py

Parse Markdown and extract structured data:
bash
python parse_markdown.py <markdown_file> [--output json|html] [--html-only]
Returns JSON with: title, cover_image, content_images (with block_index for positioning), html, total_blocks
解析Markdown并提取结构化数据:
bash
python parse_markdown.py <markdown_file> [--output json|html] [--html-only]
返回包含以下内容的JSON:标题、封面图、内容图片(含用于定位的block_index)、HTML、总块数

copy_to_clipboard.py

copy_to_clipboard.py

Copy image or HTML to system clipboard:
bash
undefined
将图片或HTML复制到系统剪贴板:
bash
undefined

Copy image (with optional compression)

复制图片(可选择压缩)

python copy_to_clipboard.py image /path/to/image.jpg [--quality 80]
python copy_to_clipboard.py image /path/to/image.jpg [--quality 80]

Copy HTML for rich text paste

复制HTML用于富文本粘贴

python copy_to_clipboard.py html --file /path/to/content.html
undefined
python copy_to_clipboard.py html --file /path/to/content.html
undefined

table_to_image.py

table_to_image.py

Convert Markdown tables to PNG images:
bash
python table_to_image.py /path/to/table.md /path/to/output.png [--style dark|light]
将Markdown表格转换为PNG图片:
bash
python table_to_image.py /path/to/table.md /path/to/output.png [--style dark|light]

Pre-Processing: Handle Unsupported Elements

预处理:处理不支持的元素

Before publishing, scan the Markdown for unsupported elements and convert them to images.
在发布之前,扫描Markdown中的不支持元素并将其转换为图片。

Step 0: Analyze Content for Limitations

步骤0:分析内容中的限制

bash
undefined
bash
undefined

Check the markdown file for unsupported elements

检查Markdown文件中的不支持元素

cat /path/to/article.md

Look for:
1. **Deep headers (H3+)**: `###`, `####`, etc.
2. **Markdown tables**: Lines with `|` characters forming table structure
3. **Mermaid code blocks**: ` ```mermaid`
cat /path/to/article.md

查找以下元素:
1. **深层标题(H3+)**:`###`、`####`等
2. **Markdown表格**:包含`|`字符形成表格结构的行
3. **Mermaid代码块**:` ```mermaid`

Converting Unsupported Elements to Images

将不支持的元素转换为图片

1. Markdown Tables → PNG

1. Markdown表格 → PNG

When a table is detected:
bash
undefined
当检测到表格时:
bash
undefined

1. Extract table to temp file

1. 将表格提取到临时文件

cat > /tmp/table.md << 'TABLE_EOF'
Column 1Column 2Column 3
Data 1Data 2Data 3
TABLE_EOF
cat > /tmp/table.md << 'TABLE_EOF'
Column 1Column 2Column 3
Data 1Data 2Data 3
TABLE_EOF

2. Convert to image

2. 转换为图片

python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table.md /tmp/table-001.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table.md /tmp/table-001.png

3. Replace table in markdown with image reference

3. 将Markdown中的表格替换为图片引用

Table description

Table description

undefined
undefined

2. Mermaid Diagrams → PNG

2. Mermaid图表 → PNG

When a mermaid block is detected:
bash
undefined
当检测到Mermaid代码块时:
bash
undefined

1. Extract mermaid to temp file

1. 将Mermaid代码提取到临时文件

cat > /tmp/diagram.mmd << 'MERMAID_EOF' flowchart TD A[Start] --> B[Process] B --> C[End] MERMAID_EOF
cat > /tmp/diagram.mmd << 'MERMAID_EOF' flowchart TD A[Start] --> B[Process] B --> C[End] MERMAID_EOF

2. Convert to image using mermaid-cli

2. 使用mermaid-cli转换为图片

mmdc -i /tmp/diagram.mmd -o /tmp/diagram-001.png -b white -s 2
mmdc -i /tmp/diagram.mmd -o /tmp/diagram-001.png -b white -s 2

3. Replace mermaid block in markdown with image reference

3. 将Markdown中的Mermaid代码块替换为图片引用

Diagram description

Diagram description

undefined
undefined

3. Deep Headers (H3+) → Simplified Structure

3. 深层标题(H3+)→ 简化结构

Goal: Preserve the article's logical structure and readability while working within X Premium's H2-only limitation.
Guidelines for the AI:
When you encounter H3, H4, or deeper headers in a Premium user's article, think about what the author intended:
  • If the header introduces a distinct subtopic under a section, convert it to bold text as a paragraph opener. This maintains visual hierarchy without breaking X's formatting.
  • If the header is a major section that happens to be H3, consider promoting it to H2 — but only if this doesn't create a flat, meaningless structure. The article should still flow logically.
  • If there's a deep hierarchy (H2 → H3 → H4), flatten thoughtfully:
    • Keep H2 as H2
    • Convert H3 to bold paragraph
    • Convert H4 to italic or just merge into the paragraph naturally
  • Preserve meaning over structure. A header like
    ### Why This Matters
    might become a bold lead-in:
    **Why does this matter?**
    followed by the content. Use your judgment.
  • Read the content. If an H3 header is just "Example" or "Note", it might work better as a blockquote or inline emphasis rather than a standalone bold line.
The goal is not mechanical conversion — it's creating an article that reads well on X while honoring the author's intent.
目标:在X的格式限制内,保留文章的逻辑结构和可读性。
AI处理指南
当在Premium用户的文章中遇到H3、H4或更深层级的标题时,思考作者的意图:
  • 如果标题是某个小节下的独立子主题,将其转换为粗体文本作为段落开头。这样既保持了视觉层次,又不会破坏X的格式。
  • 如果标题是一个主要小节但被设为H3,可以考虑将其提升为H2——但前提是这不会导致结构扁平化、失去意义。文章仍需保持逻辑流畅。
  • 如果存在深层层级结构(H2 → H3 → H4),需谨慎扁平化:
    • 保留H2为H2
    • 将H3转换为粗体段落开头
    • 将H4转换为斜体或自然融入段落
  • 优先保留含义而非结构。类似
    ### Why This Matters
    的标题可以转换为粗体引导句:
    **为什么这很重要?**
    ,后面跟上内容。请根据实际情况判断。
  • 阅读内容。如果H3标题只是“示例”或“注意”,作为块引用或行内强调可能比单独的粗体行效果更好。
我们的目标不是机械转换,而是创建一篇在X上阅读体验良好,同时尊重作者意图的文章。

Pre-Processing Workflow

预处理工作流

Before publishing, read through the article and prepare it for X:
  1. Understand the article's structure — Read it first. What are the main sections? How does the author use headers to organize ideas?
  2. Handle tables and mermaid diagrams — These need to become images. Extract each one, convert to PNG, and note where they should be inserted.
  3. Adapt headers for the subscription tier:
    • For Premium+ users: Keep headers as-is (H3+ supported)
    • For Premium users: Thoughtfully restructure H3+ headers while preserving the article's flow and intent (see guidelines above)
  4. Create the modified markdown — Save your adapted version to a temp file, ready for parsing.
The goal is an article that reads naturally on X, not a mechanically transformed document.
发布前,通读文章并为X做准备:
  1. 理解文章结构——先阅读全文。主要小节有哪些?作者如何使用标题组织观点?
  2. 处理表格和Mermaid图表——这些需要转换为图片。提取每个元素,转换为PNG,并记录它们的插入位置。
  3. 根据订阅类型调整标题:
    • 对于Premium+用户:保留标题原样(支持H3+)
    • 对于Premium用户:在保留文章流畅性和意图的前提下,合理重构H3+标题(参见上述指南)
  4. 创建修改后的Markdown——将调整后的版本保存到临时文件,以备解析。
目标是让文章在X上自然阅读,而非机械转换的文档。

Main Workflow

主要工作流

Strategy: "先文后图后分割线" (Text First, Images Second, Dividers Last)
For articles with images and dividers, paste ALL text content first, then insert images and dividers at correct positions using block index.
  1. Pre-process: Convert tables/mermaid to images, flatten deep headers
  2. Parse modified Markdown with Python script → get title, images, dividers (all with block_index), HTML
  3. Navigate to X Articles editor
  4. Upload cover image (first image)
  5. Fill title
  6. Copy HTML to clipboard (Python) → Paste with Cmd+V
  7. Insert content images at positions specified by block_index
  8. Insert dividers at positions specified by block_index (via Insert > Divider menu)
  9. Save as draft (NEVER auto-publish)
策略:"先文后图后分割线"(Text First, Images Second, Dividers Last)
对于包含图片和分割线的文章,先粘贴所有文本内容,然后根据块索引在正确位置插入图片和分割线。
  1. 预处理:将表格/Mermaid图表转换为图片,扁平化深层标题
  2. 使用Python脚本解析修改后的Markdown → 获取标题、图片、分割线(均含块索引)、HTML
  3. 导航到X Articles编辑器
  4. 上传封面图(第一张图片)
  5. 填写标题
  6. 使用Python将HTML复制到剪贴板 → 按Cmd+V粘贴
  7. 根据块索引在正确位置插入内容图片和分割线
  8. 通过菜单插入分割线(使用块索引定位)
  9. 保存为草稿(切勿自动发布)

高效执行原则 (Efficiency Guidelines)

高效执行原则 (Efficiency Guidelines)

目标: 最小化操作之间的等待时间,实现流畅的自动化体验。
目标: 最小化操作之间的等待时间,实现流畅的自动化体验。

1. 避免不必要的 browser_snapshot

1. 避免不必要的browser_snapshot

大多数浏览器操作(click, type, press_key 等)都会在返回结果中包含页面状态。不要在每次操作后单独调用
browser_snapshot
,直接使用操作返回的页面状态即可。
❌ 错误做法:
browser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...

✅ 正确做法:
browser_click → 从返回结果中获取页面状态 → browser_click → ...
大多数浏览器操作(click、type、press_key等)都会在返回结果中包含页面状态。不要在每次操作后单独调用
browser_snapshot
,直接使用操作返回的页面状态即可。
❌ 错误做法:
browser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...

✅ 正确做法:
browser_click → 从返回结果中获取页面状态 → browser_click → ...

2. 避免不必要的 browser_wait_for

2. 避免不必要的browser_wait_for

只在以下情况使用
browser_wait_for
  • 等待图片上传完成(
    textGone="正在上传媒体"
  • 等待页面初始加载(极少数情况)
不要使用
browser_wait_for
来等待按钮或输入框出现 - 它们在页面加载完成后立即可用。
仅在以下情况使用
browser_wait_for
  • 等待图片上传完成(
    textGone="正在上传媒体"
  • 等待页面初始加载(极少数情况)
不要使用
browser_wait_for
等待按钮或输入框出现——页面加载完成后它们立即可用。

3. 并行执行独立操作

3. 并行执行独立操作

当两个操作没有依赖关系时,可以在同一个消息中并行调用多个工具:
✅ 可以并行:
- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)
- 解析Markdown生成JSON + 生成HTML文件

❌ 不能并行(有依赖):
- 必须先点击create才能上传封面图
- 必须先粘贴内容才能插入图片
当两个操作没有依赖关系时,可以在同一个消息中并行调用多个工具:
✅ 可以并行:
- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)
- 解析Markdown生成JSON + 生成HTML文件

❌ 不能并行(有依赖):
- 必须先点击create才能上传封面图
- 必须先粘贴内容才能插入图片

4. 连续执行浏览器操作

4. 连续执行浏览器操作

每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作:
undefined
每个浏览器操作返回的页面状态包含所有需要的元素引用。直接使用这些引用进行下一步操作:
undefined

理想流程(每步直接执行,不额外等待):

理想流程(每步直接执行,不额外等待):

browser_navigate → 从返回状态找create按钮 → browser_click(create) → 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload → 从返回状态找应用按钮 → browser_click(应用) → 从返回状态找标题框 → browser_type(标题) → 点击编辑器 → browser_press_key(Meta+v) → ...
undefined
browser_navigate → 从返回状态找create按钮 → browser_click(create) → 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload → 从返回状态找应用按钮 → browser_click(应用) → 从返回状态找标题框 → browser_type(标题) → 点击编辑器 → browser_press_key(Meta+v) → ...
undefined

5. 准备工作前置

5. 准备工作前置

在开始浏览器操作之前,先完成所有准备工作:
  1. 扫描不支持的元素(表格、Mermaid、深层标题)
  2. 转换表格/Mermaid 为图片
  3. 解析 Markdown 获取 JSON 数据
  4. 生成 HTML 文件到 /tmp/
  5. 记录 title、cover_image、content_images 等信息
这样浏览器操作阶段可以连续执行,不需要中途停下来处理数据。
在开始浏览器操作之前,先完成所有准备工作:
  1. 扫描不支持的元素(表格、Mermaid、深层标题)
  2. 转换表格/Mermaid 为图片
  3. 解析Markdown获取JSON数据
  4. 生成HTML文件到/tmp/
  5. 记录title、cover_image、content_images等信息
这样浏览器操作阶段可以连续执行,不需要中途停下来处理数据。

Step 0: Read and Adapt the Article

步骤0:阅读并调整文章

First, read the article. Understand what it's about, how it's structured, and what the author is trying to communicate.
首先,阅读文章。 理解文章主题、结构以及作者想要传达的内容。

Preserve the Original

保留原文

IMPORTANT: Never modify the user's original file. If adaptations are needed:
  1. Save the adapted version as a copy (e.g.,
    /tmp/article_adapted.md
    or alongside the original as
    article_for_x.md
    )
  2. Tell the user what was changed and where both files are:
    I've adapted your article for X Premium. Here's what changed:
    - Converted 2 tables to images
    - Restructured 3 H3 headers to bold text for better flow
    
    Original preserved: /path/to/article.md
    Adapted version: /path/to/article_for_x.md
  3. Proceed with the adapted copy for publishing
This ensures the user can review the changes and keeps their original work intact.
重要:切勿修改用户的原始文件。如果需要调整:
  1. 将调整后的版本保存为副本(例如
    /tmp/article_adapted.md
    或在原文件旁保存为
    article_for_x.md
  2. 告知用户修改内容以及两个文件的位置:
    我已为X Premium调整了您的文章。修改内容如下:
    - 将2个表格转换为图片
    - 将3个H3标题重构为粗体文本以提升流畅性
    
    原文位置:/path/to/article.md
    调整后版本:/path/to/article_for_x.md
  3. 使用调整后的副本进行发布
这样用户可以查看修改内容,同时保留原始文件不受影响。

Adaptation Based on Subscription

根据订阅类型调整

For Premium Users (Basic Tier)

针对Premium用户(基础版)

Ask yourself:
  • Are there tables? → Convert each to a PNG image
  • Are there mermaid diagrams? → Convert each to a PNG image
  • Are there H3+ headers? → Restructure them thoughtfully (see header guidelines above)
Create a modified version of the markdown that will work within Premium's limitations while preserving readability.
自问:
  • 文章中有表格吗?→ 将每个表格转换为PNG图片
  • 文章中有Mermaid图表吗?→ 将每个图表转换为PNG图片
  • 文章中有H3及以上标题吗?→ 合理重构这些标题(参见上述标题指南)
创建一个符合Premium版限制,同时保持可读性的修改版Markdown。

For Premium+ Users

针对Premium+用户

Ask yourself:
  • Are there mermaid diagrams? → Convert to PNG (still not supported on any tier)
  • Tables and H3+ headers can stay as-is
自问:
  • 文章中有Mermaid图表吗?→ 转换为PNG图片(所有版本均不支持)
  • 表格和H3及以上标题可以保留原样

Converting Elements to Images

将元素转换为图片

bash
undefined
bash
undefined

Tables → PNG

表格 → PNG

python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png

Mermaid → PNG

Mermaid → PNG

mmdc -i /tmp/diagram-1.mmd -o /tmp/diagram-1.png -b white -s 2

Replace these elements in the markdown with image references, positioning them where the original element was.
mmdc -i /tmp/diagram-1.mmd -o /tmp/diagram-1.png -b white -s 2

在Markdown中用图片引用替换这些元素,并保持它们在原文中的位置。

Step 1: Parse Markdown (Python)

步骤1:解析Markdown(Python)

Use
parse_markdown.py
to extract all structured data:
bash
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /path/to/modified_article.md
Output JSON:
json
{
  "title": "Article Title",
  "cover_image": "/path/to/first-image.jpg",
  "content_images": [
    {"path": "/tmp/table-1.png", "block_index": 5, "after_text": "context..."},
    {"path": "/tmp/mermaid-1.png", "block_index": 12, "after_text": "another context..."}
  ],
  "dividers": [
    {"block_index": 7, "after_text": "context before divider..."},
    {"block_index": 15, "after_text": "another context..."}
  ],
  "html": "<p>Content...</p><h2>Section</h2>...",
  "total_blocks": 45
}
Key fields:
  • block_index
    : The image/divider should be inserted AFTER block element at this index (0-indexed)
  • total_blocks
    : Total number of block elements in the HTML
  • after_text
    : Kept for reference/debugging only, NOT for positioning
  • dividers
    : Array of divider positions (markdown
    ---
    must be inserted via X's menu, not HTML
    <hr>
    )
Save HTML to temp file for clipboard:
bash
python parse_markdown.py modified_article.md --html-only > /tmp/article_html.html
使用
parse_markdown.py
提取所有结构化数据:
bash
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /path/to/modified_article.md
输出JSON:
json
{
  "title": "Article Title",
  "cover_image": "/path/to/first-image.jpg",
  "content_images": [
    {"path": "/tmp/table-1.png", "block_index": 5, "after_text": "context..."},
    {"path": "/tmp/mermaid-1.png", "block_index": 12, "after_text": "another context..."}
  ],
  "dividers": [
    {"block_index": 7, "after_text": "context before divider..."},
    {"block_index": 15, "after_text": "another context..."}
  ],
  "html": "<p>Content...</p><h2>Section</h2>...",
  "total_blocks": 45
}
关键字段:
  • block_index
    : 图片/分割线应插入在第N个块元素之后(从0开始计数)
  • total_blocks
    : HTML中的块元素总数
  • after_text
    : 仅用于参考/调试,不用于定位
  • dividers
    : 分割线位置数组(Markdown中的
    ---
    必须通过X的菜单插入,而非HTML
    <hr>
    标签)
将HTML保存到临时文件以备剪贴板使用:
bash
python parse_markdown.py modified_article.md --html-only > /tmp/article_html.html

Step 2: Open X Articles Editor

步骤2:打开X Articles编辑器

browser_navigate: https://x.com/compose/articles
重要: 页面加载后会显示草稿列表,不是编辑器。需要:
  1. 等待页面加载完成: 使用
    browser_snapshot
    检查页面状态
  2. 立即点击 "create" 按钮: 不要等待 "添加标题" 等编辑器元素,它们只有点击 create 后才出现
  3. 等待编辑器加载: 点击 create 后,等待编辑器元素出现
undefined
browser_navigate: https://x.com/compose/articles
重要: 页面加载后会显示草稿列表,而非编辑器。需要:
  1. 等待页面加载完成: 使用
    browser_snapshot
    检查页面状态
  2. 立即点击"create"按钮: 不要等待“添加标题”等编辑器元素,这些元素只有点击create后才会出现
  3. 等待编辑器加载: 点击create后,等待编辑器元素出现
undefined

1. 导航到页面

1. 导航到页面

2. 获取页面快照,找到 create 按钮

2. 获取页面快照,找到create按钮

browser_snapshot
browser_snapshot

3. 点击 create 按钮(通常 ref 类似 "create" 或带有 create 标签)

3. 点击create按钮(通常ref类似"create"或带有create标签)

browser_click: element="create button", ref=<create_button_ref>
browser_click: element="create button", ref=<create_button_ref>

4. 现在编辑器应该打开了,可以继续上传封面图等操作

4. 现在编辑器应该已打开,可以继续上传封面图等操作


**注意**: 不要使用 `browser_wait_for text="添加标题"` 来等待页面加载,因为这个文本只有在点击 create 后才出现,会导致超时。

If login needed, prompt user to log in manually.

**注意**: 不要使用`browser_wait_for text="添加标题"`等待页面加载,因为该文本只有点击create后才会出现,会导致超时。

如果需要登录,请提示用户手动登录。

Step 3: Upload Cover Image

步骤3:上传封面图

  1. Click "添加照片或视频" button
  2. Use browser_file_upload with the cover image path (from JSON output)
  3. Verify image uploaded
  1. 点击“添加照片或视频”按钮
  2. 使用browser_file_upload上传封面图(来自JSON输出的路径)
  3. 验证图片上传完成

Step 4: Fill Title

步骤4:填写标题

  • Find textbox with "添加标题" placeholder
  • Use browser_type to input title (from JSON output)
  • 找到带有“添加标题”占位符的文本框
  • 使用browser_type输入标题(来自JSON输出)

Step 5: Paste Text Content (Python Clipboard)

步骤5:粘贴文本内容(Python剪贴板)

Copy HTML to system clipboard using Python, then paste:
bash
undefined
使用Python将HTML复制到系统剪贴板,然后粘贴:
bash
undefined

Copy HTML to clipboard

将HTML复制到剪贴板

python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html

Then in browser:
browser_click on editor textbox browser_press_key: Meta+v

This preserves all rich text formatting (H2, bold, links, lists).
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html

然后在浏览器中执行:
browser_click on editor textbox browser_press_key: Meta+v

这样可以保留所有富文本格式(H2、粗体、链接、列表)。

Step 6: Insert Content Images (Block Index Positioning)

步骤6:插入内容图片(按块索引定位)

关键改进: 使用
block_index
精确定位,而非依赖文字匹配。
关键改进: 使用
block_index
精确定位,而非依赖文字匹配。

定位原理

定位原理

粘贴 HTML 后,编辑器中的内容结构为一系列块元素(段落、标题、引用等)。每张图片的
block_index
表示它应该插入在第 N 个块元素之后。
粘贴HTML后,编辑器中的内容由一系列块元素(段落、标题、引用等)组成。每张图片的
block_index
表示它应该插入在第N个块元素之后。

操作步骤

操作步骤

  1. 获取所有块元素: 使用 browser_snapshot 获取编辑器内容,找到 textbox 下的所有子元素
  2. 按索引定位: 根据
    block_index
    点击对应的块元素
  3. 粘贴图片: 复制图片到剪贴板后粘贴
For each content image (from
content_images
array):
bash
undefined
  1. 获取所有块元素: 使用browser_snapshot获取编辑器内容,找到textbox下的所有子元素
  2. 按索引定位: 根据
    block_index
    点击对应的块元素
  3. 粘贴图片: 将图片复制到剪贴板后粘贴
对于每个内容图片(来自
content_images
数组):
bash
undefined

1. Copy image to clipboard (with compression)

1. 将图片复制到剪贴板(带压缩)

python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py image /path/to/img.jpg --quality 85
undefined
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py image /path/to/img.jpg --quality 85
undefined

2. Click the block element at block_index

2. 点击block_index对应的块元素

Example: if block_index=5, click the 6th block element (0-indexed)

示例:如果block_index=5,点击第6个块元素(从0开始计数)

browser_click on the element at position block_index in the editor
browser_click on the element at position block_index in the editor

3. Paste image

3. 粘贴图片

browser_press_key: Meta+v
browser_press_key: Meta+v

4. Wait for upload (use short time, returns immediately when done)

4. 等待上传完成(短时间等待,完成后立即返回)

browser_wait_for textGone="正在上传媒体" time=2
undefined
browser_wait_for textGone="正在上传媒体" time=2
undefined

反向插入

反向插入

注意: 每插入一张图片后,后续图片的实际位置会偏移。建议按
block_index
从大到小的顺序插入图片。
如果有3张图片,block_index 分别为 5, 12, 27:
  1. 先插入 block_index=27 的图片
  2. 再插入 block_index=12 的图片
  3. 最后插入 block_index=5 的图片
注意: 每插入一张图片后,后续图片的实际位置会偏移。建议按
block_index
从大到小的顺序插入图片。
如果有3张图片,block_index分别为5、12、27:
  1. 先插入block_index=27的图片
  2. 再插入block_index=12的图片
  3. 最后插入block_index=5的图片

Step 6.5: Insert Dividers (Via Menu)

步骤6.5:插入分割线(通过菜单)

重要: Markdown 中的
---
分割线不能通过 HTML
<hr>
标签粘贴(X Articles 会忽略它)。必须通过 X Articles 的 Insert 菜单插入。
重要: Markdown中的
---
分割线不能通过HTML
<hr>
标签粘贴(X Articles会忽略它)。必须通过X Articles的Insert菜单插入。

为什么需要特殊处理

为什么需要特殊处理

X Articles 有自己的原生分割线元素,只能通过 Insert > Divider 菜单插入。HTML
<hr>
标签会被完全忽略。
X Articles有自己的原生分割线元素,只能通过Insert > Divider菜单插入。HTML
<hr>
标签会被完全忽略。

操作步骤

操作步骤

For each divider (from
dividers
array), in reverse order of block_index:
undefined
对于每个分割线(来自
dividers
数组),按
block_index
从大到小的顺序插入:
undefined

1. Click the block element at block_index position

1. 点击block_index位置的块元素

browser_click on the element at position block_index in the editor
browser_click on the element at position block_index in the editor

2. Open Insert menu

2. 打开Insert菜单

browser_click on "Insert" button (Add Media button)
browser_click on "Insert" button(添加媒体按钮)

3. Click Divider menu item

3. 点击Divider菜单项

browser_click on "Divider" menuitem
browser_click on "Divider" menuitem

Divider is inserted at cursor position

分割线会插入到光标位置

undefined
undefined

反向插入

反向插入

和图片一样,按
block_index
从大到小的顺序插入分割线,避免位置偏移问题。
和图片一样,按
block_index
从大到小的顺序插入分割线,避免位置偏移问题。

与图片的插入顺序

与图片的插入顺序

建议先插入所有图片,再插入所有分割线。两者都按 block_index 从大到小的顺序:
  1. 插入所有图片(从最大 block_index 开始)
  2. 插入所有分割线(从最大 block_index 开始)
建议先插入所有图片,再插入所有分割线。两者都按block_index从大到小的顺序:
  1. 插入所有图片(从最大的block_index开始)
  2. 插入所有分割线(从最大的block_index开始)

Step 7: Save Draft

步骤7:保存草稿

  1. Verify content pasted (check word count indicator)
  2. Draft auto-saves, or click Save button if needed
  3. Click "预览" to verify formatting
  4. Report: "Draft saved. Review and publish manually."
  1. 验证内容已粘贴(检查字数统计指示器)
  2. 草稿会自动保存,如有需要可点击Save按钮
  3. 点击“预览”验证格式
  4. 告知用户:“草稿已保存。请查看并手动发布。”

Critical Rules

关键规则

  1. NEVER publish - Only save draft
  2. Pre-process first - Convert tables/mermaid/deep headers before parsing
  3. First image = cover - Upload first image as cover image
  4. Rich text conversion - Always convert Markdown to HTML before pasting
  5. Use clipboard API - Paste via clipboard for proper formatting
  6. Block index positioning - Use block_index for precise image/divider placement
  7. Reverse order insertion - Insert images and dividers from highest to lowest block_index
  8. H1 title handling - H1 is used as title only, not included in body
  9. Dividers via menu - Markdown
    ---
    must be inserted via Insert > Divider menu (HTML
    <hr>
    is ignored)
  1. 切勿自动发布 - 仅保存为草稿
  2. 先预处理 - 解析前先转换表格/Mermaid图表/深层标题
  3. 第一张图片作为封面 - 上传第一张图片作为封面
  4. 富文本转换 - 发布前始终将Markdown转换为HTML
  5. 使用剪贴板API - 通过剪贴板粘贴以保证格式正确
  6. 按块索引定位 - 使用block_index精确定位图片/分割线
  7. 反向插入 - 按block_index从大到小的顺序插入图片和分割线
  8. H1标题处理 - H1仅用作标题,不包含在正文中
  9. 通过菜单插入分割线 - Markdown中的
    ---
    必须通过Insert > Divider菜单插入(HTML
    <hr>
    会被忽略)

Supported Formatting (After Pre-Processing)

支持的格式(预处理后)

ElementSupportNotes
H2 (
##
)
NativeSection headers
Bold (
**
)
NativeStrong emphasis
Italic (
*
)
NativeEmphasis
Links (
[](url)
)
NativeHyperlinks
Ordered listsNative1. 2. 3.
Unordered listsNative- bullets
Blockquotes (
>
)
NativeQuoted text
Code blocksConverted→ Blockquotes
TablesConverted→ PNG images
MermaidConverted→ PNG images
H3+ headersConverted→ H2 or bold
Dividers (
---
)
Menu insert→ Insert > Divider
元素支持情况说明
H2 (
##
)
原生支持小节标题
粗体 (
**
)
原生支持强强调
斜体 (
*
)
原生支持强调
链接 (
[](url)
)
原生支持超链接
有序列表原生支持1. 2. 3.
无序列表原生支持- 项目符号
块引用 (
>
)
原生支持引用文本
代码块转换后支持→ 块引用
表格转换后支持→ PNG图片
Mermaid图表转换后支持→ PNG图片
H3及以上标题转换后支持→ H2或粗体文本
分割线 (
---
)
通过菜单插入→ Insert > Divider

Example Flow

示例流程

User: "Publish /path/to/article.md to X"
bash
undefined
用户:“将/path/to/article.md发布到X”
bash
undefined

Step 0: Analyze content

步骤0:分析内容

Found: 1 table, 1 mermaid diagram, 2 H3 headers

发现:1个表格、1个Mermaid图表、2个H3标题

Step 0.1: Convert table to image

步骤0.1:将表格转换为图片

python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png
python ~/.claude/skills/publish-x-article/scripts/table_to_image.py /tmp/table-1.md /tmp/table-1.png

Step 0.2: Convert mermaid to image

步骤0.2:将Mermaid图表转换为图片

mmdc -i /tmp/mermaid-1.mmd -o /tmp/mermaid-1.png -b white -s 2
mmdc -i /tmp/mermaid-1.mmd -o /tmp/mermaid-1.png -b white -s 2

Step 0.3: Create modified markdown with image refs and flattened headers

步骤0.3:创建包含图片引用和扁平化标题的修改版Markdown

Save to /tmp/article_modified.md

保存到/tmp/article_modified.md

Step 1: Parse modified markdown

步骤1:解析修改后的Markdown

python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md > /tmp/article.json python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md --html-only > /tmp/article_html.html

2. Navigate to https://x.com/compose/articles
3. Click create, upload cover image (browser_file_upload for cover only)
4. Fill title (from JSON: `title`)
5. Copy & paste HTML:
   ```bash
   python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html
Then: browser_press_key Meta+v 6. For each content image (including converted table/mermaid PNGs), in reverse order of block_index:
bash
python copy_to_clipboard.py image /path/to/img.jpg --quality 85
  • Click block element at
    block_index
    position
  • browser_press_key Meta+v
  • Wait until upload complete
  1. Verify in preview
  2. "Draft saved. Please review and publish manually."
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md > /tmp/article.json python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md --html-only > /tmp/article_html.html

2. 导航到https://x.com/compose/articles
3. 点击create,上传封面图(仅封面图使用browser_file_upload)
4. 填写标题(来自JSON中的`title`)
5. 复制并粘贴HTML:
   ```bash
   python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html
然后执行:browser_press_key Meta+v 6. 对于每个内容图片(包括转换后的表格/Mermaid PNG),按block_index从大到小的顺序
bash
python copy_to_clipboard.py image /path/to/img.jpg --quality 85
  • 点击block_index位置的块元素
  • browser_press_key Meta+v
  • 等待上传完成
  1. 在预览中验证
  2. 告知用户:“草稿已保存。请查看并手动发布。”

Best Practices

最佳实践

为什么用 block_index 而非文字匹配?

为什么使用block_index而非文字匹配?

  1. 精确定位: 不依赖文字内容,即使多处文字相似也能正确定位
  2. 可靠性: 索引是确定性的,不会因为文字相似而混淆
  3. 调试方便:
    after_text
    仍保留用于人工核验
  1. 精确定位: 不依赖文字内容,即使多处文字相似也能正确定位
  2. 可靠性: 索引是确定性的,不会因文字相似而混淆
  3. 调试方便:
    after_text
    仍保留用于人工核验

为什么用 Python 而非浏览器内 JavaScript?

为什么使用Python而非浏览器内JavaScript?

  1. 本地处理更可靠: Python 直接操作系统剪贴板,不受浏览器沙盒限制
  2. 图片压缩: 上传前压缩图片 (--quality 85),减少上传时间
  3. 代码复用: 脚本固定不变,无需每次重新编写转换逻辑
  4. 调试方便: 脚本可单独测试,问题易定位
  1. 本地处理更可靠: Python直接操作系统剪贴板,不受浏览器沙箱限制
  2. 图片压缩: 上传前压缩图片(--quality 85),减少上传时间
  3. 代码复用: 脚本固定不变,无需每次重新编写转换逻辑
  4. 调试方便: 脚本可单独测试,问题易定位

等待策略

等待策略

关键理解:
browser_wait_for
textGone
参数会在文字消失时立即返回
time
只是最大等待时间,不是固定等待时间。
undefined
关键理解:
browser_wait_for
textGone
参数会在文字消失时立即返回
time
只是最大等待时间,而非固定等待时间。
undefined

正确用法:短 time 值,条件满足立即返回

正确用法:短time值,条件满足立即返回

browser_wait_for textGone="正在上传媒体" time=2
browser_wait_for textGone="正在上传媒体" time=2

错误用法:固定长时间等待

错误用法:固定长时间等待

browser_wait_for time=5 # 无条件等待5秒,浪费时间
undefined
browser_wait_for time=5 # 无条件等待5秒,浪费时间
undefined

封面图 vs 内容图

封面图 vs 内容图

  • 封面图: 使用 browser_file_upload(因为有专门的上传按钮)
  • 内容图: 使用 Python 剪贴板 + 粘贴(更高效)
  • 封面图: 使用browser_file_upload(因为有专门的上传按钮)
  • 内容图: 使用Python剪贴板+粘贴(更高效)

Troubleshooting

故障排除

Table not rendering correctly

表格渲染不正确

  • Ensure Pillow is installed:
    pip install pillow
  • Check table markdown syntax is valid
  • 确保已安装Pillow:
    pip install pillow
  • 检查Markdown表格语法是否有效

Mermaid conversion fails

Mermaid转换失败

  • Install mermaid-cli:
    npm install -g @mermaid-js/mermaid-cli
  • Check mermaid syntax is valid
  • 安装mermaid-cli:
    npm install -g @mermaid-js/mermaid-cli
  • 检查Mermaid语法是否有效

Deep headers still showing

深层标题仍显示

  • Manually flatten
    ###
    ##
    or
    **bold**
  • Re-run pre-processing
  • 手动将
    ###
    转换为
    ##
    **粗体**
  • 重新执行预处理

Image upload timeout

图片上传超时

  • Compress images with
    --quality 70
  • Use shorter
    browser_wait_for time=2
  • 使用
    --quality 70
    压缩图片
  • 使用更短的
    browser_wait_for time=2