Skill: azfliao/weibo-publisher (version 2.0.0)

--- name: weibo-publisher description: Publish posts to Weibo (Sina Weibo) using browser automation. Use when the user wants to post content to Weibo, share updates on Weibo, publish microblogs, or automate Weibo posting. Supports text posts with emoji, hashtags, and mentions. No API key required - uses browser automation with managed browser profile. --- # Weibo Publisher Automate posting to Weibo (Sina Weibo) using browser automation through OpenClaw's managed browser. ## Prerequisites - Weibo account must be logged in via managed browser (profile="openclaw") - Browser must have active session with valid cookies ## Quick Start ### Basic Post ```python # 1. Prepare content with Unicode escape (for Chinese text) content = "刚刚解决了一个技术难题！💪" escaped_content = content.encode('unicode_escape').decode('ascii') # 2. Navigate to Weibo homepage browser(action="navigate", targetUrl="https://weibo.com/", targetId=<tab_id>) # 3. Get page snapshot to find elements browser(action="snapshot", targetId=<tab_id>) # 4. Click the post textbox (ref from snapshot, usually e31 or e136) browser(action="act", request={"kind": "click", "ref": "e31"}, targetId=<tab_id>) # 5. Type content with Unicode escape browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped_content}, targetId=<tab_id>) # 6. Get fresh snapshot to find send button browser(action="snapshot", targetId=<tab_id>) # 7. Click send button (ref from snapshot, usually e32 or e194) browser(action="act", request={"kind": "click", "ref": "e32"}, targetId=<tab_id>) # 8. Wait and verify by navigating to profile sleep(3) browser(action="navigate", targetUrl="https://weibo.com/u/<your_uid>", targetId=<tab_id>) browser(action="snapshot", targetId=<tab_id>) ``` ## Element References Common element references on Weibo homepage (as of 2026-03-02): - **Main post textbox**: `e31` (placeholder: "有什么新鲜事想分享给大家？") - **Send button**: `e32` (text: "发送", becomes enabled after typing) - **Quick post button** (top nav): `e10` (text: "发微博") - **Quick post textbox** (popup): `e746` (when using quick post popup) - **Quick post send button**: `e804` **Important Notes**: - Element references **change frequently** between sessions - **Always take a fresh snapshot** before each operation - Refs may differ between homepage (`/`) and profile page (`/u/<uid>`) - Send button is **disabled** until content is entered ## Content Features ### Supported Content Types 1. **Plain text**: Direct text input 2. **Emoji**: Include emoji directly in text (e.g., "😊🎉") 3. **Hashtags**: Use `#topic#` format (e.g., "#微博话题#") 4. **Mentions**: Use `@username` format 5. **Line breaks**: Use `\n` in text ### Content Limits - Maximum length: ~2000 characters (Weibo's limit) - Recommended length: 140-280 characters for better engagement ## Workflows ### Workflow 1: Simple Post Use the main homepage textbox for quick posts: 1. Open `https://weibo.com/` 2. Snapshot to get element refs 3. Click textbox (e136) 4. Type content 5. Click send (e194) 6. Verify success ### Workflow 2: Quick Post (Popup) Use the "发微博" button for popup posting: 1. Open `https://weibo.com/` 2. Click "发微博" button (usually e75) 3. Snapshot to get popup element refs 4. Type in popup textbox (e1028) 5. Click popup send button (e1086) 6. Verify success ### Workflow 3: Scheduled Post For posts to be published later: 1. Follow Workflow 1 or 2 to enter content 2. Click "定时微博" icon (clock icon, ref varies) 3. Select date and time 4. Click send ## State Management Track posting history in `memory/weibo-state.json`: ```json { "lastPublishTime": 1740880260, "lastPublishDate": "2026-03-02T12:38:00+08:00", "lastContent": "Your last post content..." } ``` Update this file after each successful post. ## Error Handling ### Common Issues 1. **"request: must be object" validation error** - Symptom: `Validation failed for tool "browser": - request: must be object` - Cause: Chinese quotation marks in text causing JSON parsing failure - Solution: **Use Unicode escape** for all Chinese characters (see Technical Details) 2. **Login expired** - Symptom: Redirected to login page - Solution: Manually log in via browser, then retry 3. **Send button disabled** - Symptom: Button has `disabled` attribute - Solution: Check if textbox is empty or content violates rules 4. **Element refs changed** - Symptom: Elements not found with old refs - Solution: Take fresh snapshot and use updated refs 5. **Content rejected** - Symptom: Error message after clicking send - Solution: Check for sensitive words, adjust content 6. **Post not appearing** - Symptom: No error but post doesn't show on timeline - Solution: Wait 5-10 seconds, refresh page, check if content triggered review ## Best Practices 1. **Always use Unicode escape for Chinese**: Prevents JSON parsing errors with quotation marks 2. **Always snapshot first**: Element refs change frequently between sessions 3. **Separate operations**: Click textbox → Type content → Snapshot → Click send (don't combine) 4. **Verify after posting**: Navigate to profile page and snapshot to confirm post appears 5. **Rate limiting**: Wait at least 60 seconds between posts to avoid restrictions 6. **Content quality**: Keep posts engaging, use hashtags for visibility 7. **State tracking**: Always update weibo-state.json after successful posts 8. **Handle emoji properly**: Emoji work in Unicode escape format (e.g., `\ud83d\udcaa` for 💪) ## Technical Details ### Browser Automation - **Profile**: `openclaw` (managed browser) - **Method**: Chrome DevTools Protocol (CDP) - **Session**: Cookie-based, persists across restarts - **No API needed**: Pure browser automation ### Request Format **Critical**: The `request` parameter must be a JSON object, not a string: ```javascript // ✅ Correct request={"kind": "type", "ref": "e136", "text": "content"} // ❌ Wrong request="{\"kind\": \"type\", \"ref\": \"e136\", \"text\": \"content\"}" ``` ### Unicode Escape for Chinese Content (IMPORTANT!) **Problem**: Chinese quotation marks (""、'') in JSON text can cause parsing errors. **Solution**: Use Unicode escape (`\uXXXX`) for all Chinese characters: ```python # Convert Chinese text to Unicode escape text = "刚刚解决了一个技术难题，感觉特别有成就感！" escaped = text.encode('unicode_escape').decode('ascii') # Result: \u521a\u521a\u89e3\u51b3\u4e86... ``` **Example**: ```javascript // ✅ Correct - Unicode escaped request={"kind": "type", "ref": "e31", "text": "\u521a\u521a\u89e3\u51b3\u4e86\u4e00\u4e2a\u6280\u672f\u96be\u9898"} // ❌ Wrong - Direct Chinese with quotes request={"kind": "type", "ref": "e31", "text": "刚刚解决了一个"技术难题""} ``` **Why**: Chinese quotation marks conflict with JSON string delimiters, causing the `request` parameter to be serialized as a string instead of an object. ## Reference Files - **[EXAMPLES.md](references/EXAMPLES.md)**: Real-world posting examples (including Unicode escape examples) - **[TROUBLESHOOTING.md](references/TROUBLESHOOTING.md)**: Detailed error solutions (including critical Issue 11 & 12) - **[UNICODE_ESCAPE.md](references/UNICODE_ESCAPE.md)**: Complete guide to Unicode escape for Chinese content ## Scripts - **[post_weibo.py](scripts/post_weibo.py)**: Standalone Python script for posting (optional)

path: CHANGELOG.md
content: # Weibo Publisher Skill - Changelog

## Version 2.0 (2026-03-02)

### 🎉 Major Updates

#### Critical Bug Fix: Unicode Escape Requirement
- **Problem**: Chinese quotation marks (""'') caused JSON parsing errors
- **Error**: `Validation failed for tool "browser": - request: must be object`
- **Solution**: Implemented Unicode escape for all Chinese content
- **Impact**: Enables reliable posting of Chinese content with quotation marks

#### Dynamic Element Reference Handling
- **Problem**: Element refs (e31, e136, e746) change between sessions
- **Solution**: Documented snapshot-first pattern
- **Impact**: Prevents "element not found" errors

### 📝 Documentation Updates

#### New Files
1. **UNICODE_ESCAPE.md** - Complete guide to Unicode escape
   - Problem statement and root cause analysis
   - Python implementation examples
   - Character support matrix
   - Troubleshooting guide

2. **QUICK_REFERENCE.md** - Copy-paste templates
   - Quick start template
   - Critical rules checklist
   - Common errors and fixes
   - Emergency recovery steps

#### Updated Files
1. **SKILL.md**
   - Added Unicode escape section
   - Updated Quick Start with Python examples
   - Updated element refs (e31, e32 vs e136, e194)
   - Enhanced error handling section
   - Updated best practices

2. **EXAMPLES.md**
   - Added Example 8: Post with Chinese quotation marks
   - Added Example 9: Technical post with emoji and hashtags
   - Added summary of best practices
   - Included real timestamps and results

3. **TROUBLESHOOTING.md**
   - Added Issue 11: "request: must be object" error
   - Added Issue 12: Element references changed
   - Added critical issues summary
   - Included recommended workflow

### 🔧 Technical Improvements

#### Unicode Escape Implementation
```python
# Before (failed)
text = "我们总说要"活在当下""
browser(action="act", request={"kind": "type", "ref": "e31", "text": text})

# After (works)
text = "我们总说要"活在当下""
escaped = text.encode('unicode_escape').decode('ascii')
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped})
```

#### Snapshot-First Pattern
```python
# Before (unreliable)
browser(action="act", request={"kind": "click", "ref": "e136"})

# After (reliable)
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
# Extract ref from snapshot
browser(action="act", request={"kind": "click", "ref": "e31"})
```

### ✅ Verified Features

- ✅ Chinese characters (汉字)
- ✅ Chinese punctuation (，。！？：；""'')
- ✅ Emoji (💪✨😊)
- ✅ Special symbols (→←↑↓)
- ✅ Hashtags (#话题#)
- ✅ Line breaks (\n)
- ✅ Mixed Chinese/English content

### 📊 Test Results

**Test Date**: 2026-03-02

| Test | Content Type | Length | Result | Time |
|------|-------------|--------|--------|------|
| 1 | Philosophical reflection | 171 chars | ✅ Success | 14:55 |
| 2 | Technical post with emoji | 114 chars | ✅ Success | 15:08 |

**Success Rate**: 100% (2/2) with Unicode escape

### 🎯 Breaking Changes

**CRITICAL**: All Chinese content must now use Unicode escape:

```python
# Old way (no longer works)
content = "中文内容"
browser(action="act", request={"kind": "type", "ref": "e31", "text": content})

# New way (required)
content = "中文内容"
escaped = content.encode('unicode_escape').decode('ascii')
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped})
```

### 📚 Migration Guide

If you have existing code:

1. **Add Unicode escape step**:
   ```python
   escaped = content.encode('unicode_escape').decode('ascii')
   ```

2. **Use escaped version in browser tool**:
   ```python
   browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped})
   ```

3. **Always snapshot before operations**:
   ```python
   snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
   # Extract current refs from snapshot
   ```

### 🐛 Known Issues

None currently. All critical issues resolved.

### 🔮 Future Improvements

- [ ] Automated ref extraction helper function
- [ ] Retry logic for transient failures
- [ ] Content validation before posting
- [ ] Scheduled posting support
- [ ] Multi-image upload support

### 📖 Documentation Structure

```
weibo-publisher/
├── SKILL.md                    # Main guide
├── QUICK_REFERENCE.md          # Quick start templates
├── CHANGELOG.md                # This file
├── references/
│   ├── EXAMPLES.md             # Real-world examples
│   ├── TROUBLESHOOTING.md      # Error solutions
│   └── UNICODE_ESCAPE.md       # Unicode escape guide
└── scripts/
    └── post_weibo.py           # Reference implementation
```

### 🙏 Acknowledgments

This update was driven by real-world usage and debugging on 2026-03-02, where we encountered and resolved critical issues with Chinese content posting.

---

## Version 1.0 (2026-03-01)

### Initial Release

- Basic Weibo posting via browser automation
- Support for text, emoji, hashtags
- State management with JSON file
- Examples and troubleshooting guide

### Known Issues (Fixed in v2.0)

- ❌ Chinese quotation marks cause JSON parsing errors
- ❌ Hardcoded element refs break when they change


path: QUICK_REFERENCE.md
content: # Weibo Publishing Quick Reference

## 🚀 Quick Start (Copy-Paste Template)

```python
# 1. Prepare content with Unicode escape
content = """你的中文内容"""
escaped = content.encode('unicode_escape').decode('ascii')

# 2. Navigate to Weibo
browser(action="navigate", targetUrl="https://weibo.com/", targetId="<TAB_ID>")
exec(command="sleep 2")

# 3. Snapshot to find textbox
browser(action="snapshot", compact=True, targetId="<TAB_ID>")
# Look for: textbox "有什么新鲜事" [ref=eXX]

# 4. Click textbox
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId="<TAB_ID>")

# 5. Type content
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped}, targetId="<TAB_ID>")

# 6. Snapshot to find send button
browser(action="snapshot", compact=True, targetId="<TAB_ID>")
# Look for: button "发送" [ref=eXX]

# 7. Click send
browser(action="act", request={"kind": "click", "ref": "e32"}, targetId="<TAB_ID>")

# 8. Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/<UID>", targetId="<TAB_ID>")
browser(action="snapshot", compact=True, targetId="<TAB_ID>")
```

## ⚠️ Critical Rules

### 1. ALWAYS Use Unicode Escape for Chinese
```python
# ✅ Correct
escaped = content.encode('unicode_escape').decode('ascii')
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped})

# ❌ Wrong - Will fail with "request: must be object"
browser(action="act", request={"kind": "type", "ref": "e31", "text": "中文内容"})
```

### 2. ALWAYS Snapshot Before Each Operation
```python
# ✅ Correct - Fresh snapshot
browser(action="snapshot", targetId=tab_id)
browser(action="act", request={"kind": "click", "ref": "e31"})

# ❌ Wrong - Hardcoded ref (will break when refs change)
browser(action="act", request={"kind": "click", "ref": "e136"})
```

### 3. ALWAYS Separate Operations
```python
# ✅ Correct - Separate click and type
browser(action="act", request={"kind": "click", "ref": "e31"})
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped})

# ❌ Wrong - Combined operations (unreliable)
browser(action="act", request={"kind": "click", "ref": "e31", "text": escaped})
```

## 📋 Common Element Refs

| Element | Common Refs | How to Find |
|---------|-------------|-------------|
| Post textbox | e31, e136, e746 | Search for "有什么新鲜事" |
| Send button | e32, e194, e804 | Search for "发送" |
| Quick post | e10, e75, e77 | Search for "发微博" |

**Note**: Refs change frequently! Always snapshot first.

## 🐛 Common Errors

### Error: "request: must be object"
**Cause**: Chinese quotation marks in text  
**Fix**: Use Unicode escape

### Error: Element not found
**Cause**: Element ref changed  
**Fix**: Take fresh snapshot, use new ref

### Error: Send button disabled
**Cause**: Empty textbox or rate limit  
**Fix**: Verify content typed, wait 60s between posts

## ✅ Verification Checklist

After posting:
- [ ] Wait 3 seconds
- [ ] Navigate to profile page
- [ ] Take snapshot
- [ ] Confirm post appears in timeline
- [ ] Update `memory/weibo-state.json`

## 📊 State File Format

```json
{
  "lastPublishTime": 1772435680,
  "lastPublishDate": "2026-03-02T15:08:00+08:00",
  "lastContent": "Your last post content..."
}
```

## 🎯 Best Practices

1. **Unicode escape**: Always for Chinese content
2. **Snapshot first**: Never hardcode refs
3. **Separate ops**: Click → Type → Snapshot → Send
4. **Verify**: Always check post appeared
5. **Rate limit**: Wait 60s between posts
6. **State tracking**: Update JSON after each post

## 📚 Full Documentation

- [SKILL.md](../SKILL.md) - Complete guide
- [UNICODE_ESCAPE.md](UNICODE_ESCAPE.md) - Unicode escape details
- [EXAMPLES.md](EXAMPLES.md) - Real-world examples
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - Error solutions

## 🔗 Quick Links

- Weibo homepage: https://weibo.com/
- Your profile: https://weibo.com/u/8397479298
- Browser tab ID: Check with `browser(action="tabs")`

## 💡 Pro Tips

1. **Emoji support**: Works perfectly with Unicode escape (💪 → `\ud83d\udcaa`)
2. **Hashtags**: Use Chinese # (＃) for proper recognition
3. **Line breaks**: Include `\n` in original text before escaping
4. **Special chars**: Arrows (→), symbols (✨) all work
5. **Content length**: 140-280 chars optimal for engagement

## 🚨 Emergency Recovery

If posting fails:
1. Check browser status: `browser(action="status")`
2. Check tabs: `browser(action="tabs")`
3. Navigate to Weibo: `browser(action="navigate", targetUrl="https://weibo.com/")`
4. Take snapshot: `browser(action="snapshot")`
5. Verify login: Look for username in snapshot
6. Retry with fresh refs

## 📅 Last Updated

2026-03-02 - Added Unicode escape requirement and dynamic ref handling


path: references/EXAMPLES.md
content: # Weibo Publishing Examples

Real-world examples from actual usage.

## Example 1: Simple Text Post

**User request**: "发一条微博：今天天气真好！"

**Implementation**:
```javascript
// 1. Open Weibo
browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")

// 2. Get snapshot
browser(action="snapshot", targetId="ABC123")

// 3. Click textbox
browser(action="act", request={"kind": "click", "ref": "e136"}, targetId="ABC123")

// 4. Type content
browser(action="act", request={"kind": "type", "ref": "e136", "text": "今天天气真好！"}, targetId="ABC123")

// 5. Click send
browser(action="act", request={"kind": "click", "ref": "e194"}, targetId="ABC123")
```

## Example 2: Post with Emoji and Hashtags

**User request**: "发微博：分享一下今天的好心情 #每日心情# 😊"

**Content**:
```
分享一下今天的好心情 #每日心情# 😊
```

**Implementation**: Same as Example 1, just change the text content.

## Example 3: Multi-line Post

**User request**: "发一条关于中东局势的评论"

**Content**:
```
中东局势再起波澜。美以联合行动后，伊朗最高领袖哈梅内伊在袭击中身亡，这标志着地区格局可能迎来深刻变革。

特朗普警告若伊朗继续报复将以"前所未有的力量"回击，而伊朗方面则呼吁复仇。

油价金价应声暴涨，全球市场神经紧绷。未来几周的走向，或将决定中东几十年的命运。

历史的转折点，往往就在这样的时刻悄然到来。
```

**Implementation**:
```javascript
browser(action="act", request={
  "kind": "type", 
  "ref": "e136", 
  "text": "中东局势再起波澜。美以联合行动后，伊朗最高领袖哈梅内伊在袭击中身亡，这标志着地区格局可能迎来深刻变革。\n\n特朗普警告若伊朗继续报复将以\"前所未有的力量\"回击，而伊朗方面则呼吁复仇。\n\n油价金价应声暴涨，全球市场神经紧绷。未来几周的走向，或将决定中东几十年的命运。\n\n历史的转折点，往往就在这样的时刻悄然到来。"
}, targetId="ABC123")
```

## Example 4: Using Quick Post Popup

**User request**: "用快捷发布窗口发微博"

**Implementation**:
```javascript
// 1. Open Weibo
browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")

// 2. Get snapshot
browser(action="snapshot", targetId="ABC123")

// 3. Click "发微博" button
browser(action="act", request={"kind": "click", "ref": "e75"}, targetId="ABC123")

// 4. Wait for popup, then snapshot again
browser(action="snapshot", targetId="ABC123")

// 5. Type in popup textbox
browser(action="act", request={"kind": "type", "ref": "e1028", "text": "Your content"}, targetId="ABC123")

// 6. Click popup send button
browser(action="act", request={"kind": "click", "ref": "e1086"}, targetId="ABC123")
```

## Example 5: Post with State Tracking

**Complete workflow with state management**:

```javascript
// 1. Read current state
const state = JSON.parse(fs.readFileSync('memory/weibo-state.json'));

// 2. Check if enough time has passed (e.g., 1 hour)
const now = Math.floor(Date.now() / 1000);
if (now - state.lastPublishTime < 3600) {
  console.log("Too soon to post again");
  return;
}

// 3. Post to Weibo (steps from Example 1)
// ... posting steps ...

// 4. Update state
const newState = {
  lastPublishTime: now,
  lastPublishDate: new Date().toISOString(),
  lastContent: "Your new post content"
};
fs.writeFileSync('memory/weibo-state.json', JSON.stringify(newState, null, 2));
```

## Example 6: Automated Hourly Posts

**User request**: "每小时自动发一条微博"

**Implementation** (in HEARTBEAT.md):
```markdown
## 微博自动发布

### 检查逻辑
1. 读取 `memory/weibo-state.json`
2. 如果距离上次发布 >= 1小时：
   - 生成新内容（基于热搜/新闻）
   - 发布微博
   - 更新状态文件

### 内容来源
- 微博热搜
- 新闻事件
- 科技动态
- 个人思考
```

## Example 7: Verification After Posting

**Always verify the post was successful**:

```javascript
// After clicking send, wait a moment then snapshot
browser(action="snapshot", targetId="ABC123")

// Look for your post in the timeline
// It should appear at the top with:
// - Your username
// - "刚刚" (just now) timestamp
// - The content you posted
// - Interaction buttons (转发/评论/赞)
```

## Common Patterns

### Pattern 1: Simple Post Function

```javascript
async function postWeibo(content) {
  // 1. Open and snapshot
  const browser = await openWeibo();
  
  // 2. Click textbox
  await clickElement(browser, "e136");
  
  // 3. Type content
  await typeText(browser, "e136", content);
  
  // 4. Click send
  await clickElement(browser, "e194");
  
  // 5. Verify
  await verifyPost(browser);
}
```

### Pattern 2: Content Generation + Post

```javascript
async function generateAndPost() {
  // 1. Generate content based on trending topics
  const content = await generateContent();
  
  // 2. Post to Weibo
  await postWeibo(content);
  
  // 3. Update state
  await updateState(content);
}
```

### Pattern 3: Scheduled Posting

```javascript
async function schedulePost(content, time) {
  // 1. Open Weibo and enter content
  await enterContent(content);
  
  // 2. Click scheduled post icon
  await clickElement(browser, "e183"); // 定时微博
  
  // 3. Set time
  await setScheduledTime(time);
  
  // 4. Confirm
  await clickElement(browser, "e194");
}
```

## Historical Posts (2026-03-01 to 2026-03-02)

### 2026-03-01
1. **19:30** - "hello, world!" (测试)
2. **19:35** - 自我介绍（包含emoji和话题标签）

### 2026-03-02
1. **00:56** - WiFi穿墙透视技术科普
2. **01:56** - 深夜思考：睡前刷手机与睡眠质量
3. **02:56** - 凌晨思考：独处与深度思考
4. **03:56** - 中东局势评论（哈梅内伊遇袭身亡）
5. **12:38** - 中东局势深度评论（美以联合行动、特朗普警告、油价金价暴涨）

---

## Example 8: Post with Chinese Quotation Marks (Unicode Escape)

**Date**: 2026-03-02 14:55

**User request**: "发布关于'活在当下'的哲学思考"

**Content**:
```
下午两点半，阳光正好。突然想到一个有趣的悖论：我们总说要"活在当下"，可当下这一秒，已经成为了过去。真正的当下，或许就是那个永远抓不住的瞬间。

与其纠结于此，不如换个角度：既然每一秒都会成为过去，那就让每一秒都值得回忆。做有意义的事，见想见的人，说想说的话。人生不就是由无数个"刚刚过去的当下"串联而成的吗？

珍惜此刻，即便它转瞬即逝。✨
```

**Key Challenge**: Chinese quotation marks (""'') cause JSON parsing errors.

**Solution**: Use Unicode escape for all Chinese characters.

**Implementation**:
```python
# Step 1: Prepare content with Unicode escape
content = """下午两点半，阳光正好。突然想到一个有趣的悖论：我们总说要"活在当下"，可当下这一秒，已经成为了过去。真正的当下，或许就是那个永远抓不住的瞬间。

与其纠结于此，不如换个角度：既然每一秒都会成为过去，那就让每一秒都值得回忆。做有意义的事，见想见的人，说想说的话。人生不就是由无数个"刚刚过去的当下"串联而成的吗？

珍惜此刻，即便它转瞬即逝。✨"""

escaped = content.encode('unicode_escape').decode('ascii')
# Result: \u4e0b\u5348\u4e24\u70b9\u534a\uff0c\u9633\u5149\u6b63\u597d...

# Step 2: Navigate to Weibo
browser(action="navigate", targetUrl="https://weibo.com/", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
exec(command="sleep 2")

# Step 3: Get snapshot
browser(action="snapshot", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found textbox ref: e746

# Step 4: Click textbox
browser(action="act", request={"kind": "click", "ref": "e746"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 5: Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": "e746", "text": escaped}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 6: Get fresh snapshot for send button
browser(action="snapshot", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found send button ref: e804

# Step 7: Click send
browser(action="act", request={"kind": "click", "ref": "e804"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 8: Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
```

**Result**: ✅ Successfully published (171 characters)

**Lessons Learned**:
1. Always use Unicode escape for Chinese content
2. Element refs change between sessions (e746 vs e136)
3. Separate click and type operations
4. Take fresh snapshot before clicking send button

---

## Example 9: Technical Post with Emoji and Hashtags (Unicode Escape)

**Date**: 2026-03-02 15:08

**User request**: "发布关于解决技术问题的感悟"

**Content**:
```
刚刚解决了一个技术难题，感觉特别有成就感！💪

编程的乐趣就在于此：遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长，每一个bug都是一个老师。

技术人的快乐，就是这么简单纯粹。✨

#编程日常 #技术分享
```

**Implementation**:
```python
# Step 1: Prepare content with Unicode escape
content = """刚刚解决了一个技术难题，感觉特别有成就感！💪

编程的乐趣就在于此：遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长，每一个bug都是一个老师。

技术人的快乐，就是这么简单纯粹。✨

#编程日常 #技术分享"""

escaped = content.encode('unicode_escape').decode('ascii')

# Step 2: Navigate to homepage
browser(action="navigate", targetUrl="https://weibo.com/", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
exec(command="sleep 2")

# Step 3: Snapshot and find textbox
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found: e31

# Step 4: Click textbox
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 5: Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 6: Fresh snapshot for send button
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found: e32

# Step 7: Click send
browser(action="act", request={"kind": "click", "ref": "e32"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")

# Step 8: Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
```

**Result**: ✅ Successfully published (114 characters)

**Key Points**:
1. Emoji (💪✨) work perfectly with Unicode escape
2. Hashtags (#编程日常#) are recognized correctly
3. Special arrows (→) display properly
4. Element refs (e31, e32) were different from previous session

---

## Summary of Best Practices (2026-03-02)

Based on successful posts:

1. **Always use Unicode escape** for Chinese content:
   ```python
   escaped = content.encode('unicode_escape').decode('ascii')
   ```

2. **Element refs change frequently**:
   - Textbox: e31, e136, e746 (varies)
   - Send button: e32, e194, e804 (varies)
   - Always snapshot first!

3. **Separate operations**:
   - Click textbox
   - Type content
   - Snapshot again
   - Click send

4. **Verification is critical**:
   - Wait 3 seconds after clicking send
   - Navigate to profile page
   - Take snapshot to confirm post appears

5. **State management**:
   - Update `memory/weibo-state.json` after each post
   - Track timestamp and content

6. **Rate limiting**:
   - Wait at least 60 seconds between posts
   - Avoid posting too frequently


path: references/TROUBLESHOOTING.md
content: # Weibo Publisher Troubleshooting

Detailed solutions for common issues.

## Issue 1: Login Expired / Not Logged In

### Symptoms
- Browser redirects to `https://passport.weibo.com/`
- Login form appears instead of homepage
- "请登录" (Please log in) message

### Solution
1. Manually log in via browser:
   ```javascript
   browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")
   ```
2. Complete login in the browser window
3. Verify login by checking for username in top-right corner
4. Retry posting

### Prevention
- Cookies persist in managed browser profile
- Login should remain valid for weeks/months
- Check login status before posting

## Issue 2: Send Button Disabled

### Symptoms
- Send button has `disabled` attribute in snapshot
- Button appears grayed out
- Clicking has no effect

### Causes & Solutions

**Cause 1: Empty textbox**
- Solution: Ensure content was typed successfully
- Verify: Take snapshot after typing, check textbox has content

**Cause 2: Content too short**
- Solution: Weibo may require minimum length (usually 1 character is enough)
- Verify: Check content length

**Cause 3: Content violates rules**
- Solution: Weibo may detect sensitive words
- Verify: Try different content
- Workaround: Use synonyms or add spaces

**Cause 4: Rate limiting**
- Solution: Wait 30-60 seconds before next post
- Verify: Check if you posted recently

## Issue 3: Element References Changed

### Symptoms
- Error: "Element not found"
- Actions fail silently
- Snapshot shows different refs

### Solution
1. Take fresh snapshot:
   ```javascript
   browser(action="snapshot", targetId="ABC123")
   ```
2. Find new element refs in snapshot output
3. Update your code with new refs

### Common Element Refs

| Element | Common Refs | How to Find |
|---------|-------------|-------------|
| Main textbox | e136, e140 | Look for `textbox "有什么新鲜事想分享给大家？"` |
| Send button | e194, e198 | Look for `button "发送"` |
| Quick post textbox | e1028, e1032 | In popup, look for textbox |
| Quick post send | e1086, e1090 | In popup, look for `button "发送"` |

### Prevention
- Always snapshot before acting
- Don't hardcode element refs
- Parse snapshot output dynamically

## Issue 4: Content Not Appearing After Post

### Symptoms
- Send button clicked successfully
- No error message
- But post doesn't appear in timeline

### Diagnosis Steps

1. **Wait and refresh**:
   ```javascript
   // Wait 2-3 seconds
   await sleep(3000);
   
   // Refresh page
   browser(action="navigate", targetUrl="https://weibo.com/", targetId="ABC123")
   
   // Snapshot to check
   browser(action="snapshot", targetId="ABC123")
   ```

2. **Check for error messages**:
   - Look for red error text in snapshot
   - Common errors: "内容违规" (content violation), "发布失败" (post failed)

3. **Verify login status**:
   - Check if still logged in
   - Look for username in snapshot

### Solutions

**If content violated rules**:
- Modify content to avoid sensitive words
- Remove URLs if they're blocked
- Try shorter content

**If rate limited**:
- Wait 5-10 minutes
- Reduce posting frequency

**If technical error**:
- Refresh page and retry
- Clear browser cache (restart managed browser)
- Re-login if needed

## Issue 5: Request Parameter Format Error

### Symptoms
- Error: "Validation failed for tool 'browser'"
- Error: "request: must be object"

### Cause
Passing `request` as a string instead of JSON object.

### Solution

**❌ Wrong**:
```javascript
browser(action="act", request="{\"kind\": \"type\", \"ref\": \"e136\", \"text\": \"content\"}")
```

**✅ Correct**:
```javascript
browser(action="act", request={"kind": "type", "ref": "e136", "text": "content"})
```

### Prevention
- Always use JSON object syntax
- Don't stringify the request parameter
- Let the tool handle serialization

## Issue 6: Special Characters in Content

### Symptoms
- Content with quotes/newlines fails
- Text appears garbled
- Emoji don't display correctly

### Solutions

**For quotes**:
```javascript
// Escape quotes in content
text: "He said \"hello\" to me"
```

**For newlines**:
```javascript
// Use \n for line breaks
text: "Line 1\nLine 2\nLine 3"
```

**For emoji**:
```javascript
// Emoji work directly, no escaping needed
text: "Hello 😊🎉"
```

**For special characters**:
```javascript
// Most Unicode characters work fine
text: "中文、日本語、한글、العربية"
```

## Issue 7: Browser Not Responding

### Symptoms
- Actions timeout
- No response from browser
- Snapshot fails

### Diagnosis
1. Check browser status:
   ```javascript
   browser(action="status")
   ```

2. Check if browser is running:
   ```bash
   ps aux | grep -i chrome
   ```

### Solutions

**If browser crashed**:
```javascript
// Restart browser
browser(action="stop", profile="openclaw")
browser(action="start", profile="openclaw")
```

**If browser is frozen**:
```bash
# Kill and restart
pkill -f "Chrome.*openclaw"
# Then start again via browser tool
```

**If CDP connection lost**:
- Close and reopen the tab
- Restart managed browser
- Check network connectivity

## Issue 8: Posting Too Frequently

### Symptoms
- Posts succeed but don't appear
- Account temporarily restricted
- "操作过于频繁" (too frequent) message

### Solution
1. **Immediate**: Stop posting for 10-15 minutes
2. **Short-term**: Reduce frequency to max 1 post per hour
3. **Long-term**: Implement rate limiting in code

### Rate Limiting Implementation

```javascript
// Check last post time
const state = JSON.parse(fs.readFileSync('memory/weibo-state.json'));
const now = Math.floor(Date.now() / 1000);
const timeSinceLastPost = now - state.lastPublishTime;

// Enforce minimum interval (e.g., 1 hour = 3600 seconds)
if (timeSinceLastPost < 3600) {
  console.log(`Too soon. Wait ${3600 - timeSinceLastPost} more seconds.`);
  return;
}

// Proceed with posting
```

### Recommended Intervals
- **Safe**: 1 post per hour
- **Moderate**: 1 post per 30 minutes
- **Risky**: More than 2 posts per hour

## Issue 9: Content Length Exceeded

### Symptoms
- Send button disabled after typing
- Character count shows red
- Warning message about length

### Solution
1. **Check length**:
   ```javascript
   if (content.length > 2000) {
     content = content.substring(0, 1997) + "...";
   }
   ```

2. **Split into multiple posts**:
   ```javascript
   const parts = splitContent(content, 2000);
   for (const part of parts) {
     await postWeibo(part);
     await sleep(60000); // Wait 1 minute between posts
   }
   ```

### Weibo Length Limits
- **Maximum**: ~2000 characters
- **Recommended**: 140-280 characters (better engagement)
- **Minimum**: 1 character

## Issue 10: Snapshot Shows Unexpected Page

### Symptoms
- Snapshot shows different page than expected
- Elements not found
- Page structure different

### Causes & Solutions

**Cause 1: Page not loaded**
- Solution: Wait for page load before snapshot
- Add delay: `await sleep(2000)`

**Cause 2: Redirected**
- Solution: Check URL in snapshot response
- Navigate back to correct page

**Cause 3: Popup/modal appeared**
- Solution: Close popup first
- Look for close button in snapshot

**Cause 4: Wrong tab**
- Solution: Verify targetId
- List tabs: `browser(action="tabs")`

## Debugging Checklist

When something goes wrong, check these in order:

1. ✅ Browser is running (`browser(action="status")`)
2. ✅ Logged into Weibo (check snapshot for username)
3. ✅ On correct page (`https://weibo.com/`)
4. ✅ Element refs are current (fresh snapshot)
5. ✅ Request format is correct (JSON object, not string)
6. ✅ Content is valid (length, no violations)
7. ✅ Not rate limited (check last post time)
8. ✅ Network is working (can load page)

## Getting Help

If issues persist:

1. **Capture full context**:
   - Take snapshot and save output
   - Note exact error messages
   - Record steps to reproduce

2. **Check recent changes**:
   - Did Weibo update their UI?
   - Did element refs change?
   - Did login expire?

3. **Try manual operation**:
   - Can you post manually in the browser?
   - If manual works, issue is in automation
   - If manual fails, issue is with account/network

4. **Review logs**:
   - Check `memory/2026-03-02.md` for recent activity
   - Look for patterns in failures
   - Compare with successful posts

---

## Issue 11: "request: must be object" Validation Error

### Symptoms
- Error message: `Validation failed for tool "browser": - request: must be object`
- Post fails before even reaching Weibo
- OpenClaw tool validation fails

### Root Cause
Chinese quotation marks (""、'') in the text content cause JSON parsing errors. The `request` parameter gets serialized as a string instead of an object.

**Example of problematic content**:
```
我们总说要"活在当下"，可当下这一秒...
            ^        ^
            These Chinese quotes break JSON parsing
```

### Solution: Use Unicode Escape

**Step 1**: Convert all Chinese characters to Unicode escape:

```python
content = "我们总说要"活在当下"，可当下这一秒..."
escaped = content.encode('unicode_escape').decode('ascii')
# Result: \u6211\u4eec\u603b\u8bf4\u8981\u201c\u6d3b\u5728\u5f53\u4e0b\u201d...
```

**Step 2**: Use the escaped version in browser tool:

```python
browser(
    action="act",
    request={"kind": "type", "ref": "e31", "text": escaped},
    targetId="881E3B870B4D7562F8573CCB5C7F0C55"
)
```

### Why This Works

Unicode escape converts characters to `\uXXXX` format, which:
- Contains no quotation marks
- Is pure ASCII (safe for JSON)
- Renders correctly in browser (Weibo displays normal Chinese)

### Complete Example

```python
# Original content with problematic quotes
content = """下午两点半，阳光正好。突然想到一个有趣的悖论：我们总说要"活在当下"，可当下这一秒，已经成为了过去。"""

# Convert to Unicode escape
escaped = content.encode('unicode_escape').decode('ascii')

# Use in browser tool - this works!
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped}, targetId=tab_id)
```

### Prevention

**Always use Unicode escape for Chinese content**:

```python
def prepare_weibo_content(text):
    """Prepare content for Weibo posting"""
    return text.encode('unicode_escape').decode('ascii')

# Usage
content = "你的中文内容"
safe_content = prepare_weibo_content(content)
```

### Related Issues

This also fixes:
- Chinese punctuation issues (，。！？：；)
- Mixed Chinese/English content
- Emoji rendering (💪✨😊)
- Special symbols (→←↑↓)

### Historical Context

This issue was discovered on 2026-03-02 after multiple failed attempts:
1. ❌ Direct Chinese text → JSON parsing error
2. ❌ Escaped JSON string → Still treated as string
3. ❌ CDP WebSocket → Connection closed
4. ✅ Unicode escape → Success!

### See Also

- [UNICODE_ESCAPE.md](UNICODE_ESCAPE.md) - Detailed guide on Unicode escape
- [EXAMPLES.md](EXAMPLES.md) - Examples 8 & 9 show successful usage

---

## Issue 12: Element References Changed

### Symptoms
- Elements not found with previously working refs
- "Element not found" errors
- Clicks/types have no effect

### Root Cause
Weibo's frontend updates element IDs dynamically. Refs like `e136`, `e31`, `e746` change between:
- Different sessions
- Different pages (homepage vs profile)
- Different times of day
- Browser restarts

### Solution: Always Snapshot First

**Never hardcode element refs**. Always follow this pattern:

```python
# Step 1: Navigate to page
browser(action="navigate", targetUrl="https://weibo.com/", targetId=tab_id)
exec(command="sleep 2")

# Step 2: Take snapshot to get current refs
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)

# Step 3: Find the textbox ref from snapshot
# Look for: textbox "有什么新鲜事想分享给大家？"
# Example output: textbox [ref=e31]

# Step 4: Use the current ref
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId=tab_id)
```

### Common Ref Variations

| Element | Observed Refs | Notes |
|---------|---------------|-------|
| Post textbox | e31, e136, e746 | Changes most frequently |
| Send button | e32, e194, e804 | Enabled only after typing |
| Quick post button | e10, e75, e77 | Top navigation |
| Profile link | e6, e49, e50 | Usually stable |

### Best Practice

Create a helper function to extract refs:

```python
def find_element_ref(snapshot_text, element_description):
    """
    Extract element ref from snapshot text
    
    Args:
        snapshot_text: Output from browser snapshot
        element_description: Text to search for (e.g., "有什么新鲜事")
    
    Returns:
        Element ref (e.g., "e31") or None
    """
    import re
    # Look for pattern: [ref=eXXX] near the description
    pattern = rf'{re.escape(element_description)}.*?\[ref=(e\d+)\]'
    match = re.search(pattern, snapshot_text, re.DOTALL)
    return match.group(1) if match else None

# Usage
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
textbox_ref = find_element_ref(snapshot, "有什么新鲜事")
send_ref = find_element_ref(snapshot, "发送")
```

### Prevention

1. **Never cache refs** across sessions
2. **Always snapshot** before each operation
3. **Verify refs** in snapshot output before using
4. **Handle missing refs** gracefully with error messages

### Recovery

If refs changed mid-operation:
1. Take fresh snapshot
2. Find new refs
3. Retry operation with new refs
4. Update any stored refs

---

## Summary: Critical Issues (2026-03-02)

The two most critical issues discovered:

### 1. Unicode Escape Required (Issue 11)
- **Impact**: Blocks all Chinese content posting
- **Solution**: Always use `text.encode('unicode_escape').decode('ascii')`
- **Priority**: CRITICAL - Must implement for every post

### 2. Dynamic Element Refs (Issue 12)
- **Impact**: Operations fail when refs change
- **Solution**: Always snapshot before each operation
- **Priority**: HIGH - Implement snapshot-first pattern

**Recommended Workflow**:
```python
# 1. Prepare content with Unicode escape
escaped = content.encode('unicode_escape').decode('ascii')

# 2. Navigate and snapshot
browser(action="navigate", targetUrl="https://weibo.com/", targetId=tab_id)
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)

# 3. Extract current refs from snapshot
textbox_ref = extract_ref(snapshot, "有什么新鲜事")

# 4. Click textbox
browser(action="act", request={"kind": "click", "ref": textbox_ref}, targetId=tab_id)

# 5. Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": textbox_ref, "text": escaped}, targetId=tab_id)

# 6. Fresh snapshot for send button
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
send_ref = extract_ref(snapshot, "发送")

# 7. Click send
browser(action="act", request={"kind": "click", "ref": send_ref}, targetId=tab_id)

# 8. Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/<uid>", targetId=tab_id)
browser(action="snapshot", compact=True, targetId=tab_id)
```

This workflow addresses both critical issues and ensures reliable posting.


path: references/UNICODE_ESCAPE.md
content: # Unicode Escape Guide for Weibo Publishing

## Problem Statement

When publishing Chinese content to Weibo using OpenClaw's browser tool, Chinese quotation marks (""、'') cause JSON parsing errors:

```
Validation failed for tool "browser": - request: must be object
```

This happens because the `request` parameter gets serialized as a string instead of an object.

## Root Cause

Chinese quotation marks conflict with JSON string delimiters:

```json
// This breaks JSON parsing:
{"text": "我说"你好""}
         ^    ^  ^  ^
         |    |  |  |
         |    |  |  +-- Unexpected quote
         |    |  +----- Unexpected quote
         |    +-------- String ends here (parser thinks)
         +------------- String starts here
```

## Solution: Unicode Escape

Convert all Chinese characters to Unicode escape sequences (`\uXXXX`):

### Python Implementation

```python
# Convert Chinese text to Unicode escape
text = "刚刚解决了一个技术难题，感觉特别有成就感！💪"
escaped = text.encode('unicode_escape').decode('ascii')

print(escaped)
# Output: \u521a\u521a\u89e3\u51b3\u4e86\u4e00\u4e2a\u6280\u672f\u96be\u9898\uff0c\u611f\u89c9\u7279\u522b\u6709\u6210\u5c31\u611f\uff01\ud83d\udcaa
```

### Usage in Browser Tool

```python
# Prepare content
content = "下午两点半，阳光正好。突然想到一个有趣的悖论：我们总说要"活在当下"..."
escaped_content = content.encode('unicode_escape').decode('ascii')

# Use in browser tool
browser(
    action="act",
    request={
        "kind": "type",
        "ref": "e31",
        "text": escaped_content  # Use escaped version
    },
    targetId="881E3B870B4D7562F8573CCB5C7F0C55"
)
```

## Complete Example

```python
#!/usr/bin/env python3
"""Complete example of posting to Weibo with Unicode escape"""

def post_to_weibo(content, target_id):
    """
    Post content to Weibo using Unicode escape
    
    Args:
        content: Original Chinese text
        target_id: Browser tab ID
    """
    # Step 1: Convert to Unicode escape
    escaped = content.encode('unicode_escape').decode('ascii')
    
    # Step 2: Navigate to Weibo homepage
    browser(action="navigate", targetUrl="https://weibo.com/", targetId=target_id)
    exec(command="sleep 2")
    
    # Step 3: Get snapshot to find textbox
    snapshot = browser(action="snapshot", compact=True, targetId=target_id)
    # Find textbox ref (usually e31)
    
    # Step 4: Click textbox
    browser(
        action="act",
        request={"kind": "click", "ref": "e31"},
        targetId=target_id
    )
    
    # Step 5: Type content with Unicode escape
    browser(
        action="act",
        request={"kind": "type", "ref": "e31", "text": escaped},
        targetId=target_id
    )
    
    # Step 6: Get fresh snapshot to find send button
    snapshot = browser(action="snapshot", compact=True, targetId=target_id)
    # Find send button ref (usually e32)
    
    # Step 7: Click send button
    browser(
        action="act",
        request={"kind": "click", "ref": "e32"},
        targetId=target_id
    )
    
    # Step 8: Wait and verify
    exec(command="sleep 3")
    browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId=target_id)
    exec(command="sleep 2")
    browser(action="snapshot", compact=True, targetId=target_id)
    
    print("✅ Post published successfully!")

# Example usage
content = """刚刚解决了一个技术难题，感觉特别有成就感！💪

编程的乐趣就在于此：遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长，每一个bug都是一个老师。

技术人的快乐，就是这么简单纯粹。✨

#编程日常 #技术分享"""

post_to_weibo(content, "881E3B870B4D7562F8573CCB5C7F0C55")
```

## Character Support

Unicode escape works for:

- ✅ Chinese characters (汉字)
- ✅ Chinese punctuation (，。！？：；""'')
- ✅ Emoji (💪✨😊)
- ✅ Special symbols (→←↑↓)
- ✅ Hashtags (#话题#)
- ✅ Line breaks (\n)

## Performance Notes

- Escaped strings are longer but parse correctly
- No performance impact on browser rendering
- Weibo displays the text normally (unescaped)

## Troubleshooting

### Issue: Emoji not displaying correctly

**Cause**: Some emoji use surrogate pairs (2 code units)

**Solution**: Python's `unicode_escape` handles this automatically:

```python
"💪".encode('unicode_escape').decode('ascii')
# Output: \ud83d\udcaa (surrogate pair)
```

### Issue: Line breaks not working

**Cause**: Need to use `\n` in the original text

**Solution**: Include line breaks before escaping:

```python
text = "Line 1\nLine 2\nLine 3"
escaped = text.encode('unicode_escape').decode('ascii')
# Output: Line 1\nLine 2\nLine 3
```

### Issue: Hashtags not recognized

**Cause**: Hashtags need Chinese # symbol (＃ U+FF03)

**Solution**: Use proper Chinese hashtag format:

```python
text = "#编程日常#"  # Chinese full-width #
escaped = text.encode('unicode_escape').decode('ascii')
# Weibo will recognize this as a hashtag
```

## Historical Context

This solution was discovered on 2026-03-02 after encountering repeated failures with direct Chinese text. Previous attempts included:

1. ❌ Direct JSON object (failed due to quote conflicts)
2. ❌ CDP WebSocket connection (connection closed)
3. ❌ JavaScript file execution (tool limitation)
4. ✅ Unicode escape (successful!)

The key insight: Chinese quotation marks break JSON parsing, but Unicode escape bypasses this entirely.

## References

- Python `unicode_escape` codec: https://docs.python.org/3/library/codecs.html#text-encodings
- Unicode standard: https://unicode.org/
- Weibo API limitations: No official API for posting (hence browser automation)


path: scripts/post_weibo.py
content: #!/usr/bin/env python3
"""
Weibo Publisher Script

A standalone Python script for posting to Weibo via browser automation.
This script can be called directly or used as a reference implementation.

Usage:
    python3 post_weibo.py "Your content here"
    python3 post_weibo.py --file content.txt
    python3 post_weibo.py --interactive

Requirements:
    - OpenClaw browser tool
    - Logged in Weibo account in managed browser (profile="openclaw")
"""

import sys
import json
import time
from datetime import datetime
from pathlib import Path

# Configuration
WEIBO_URL = "https://weibo.com/"
BROWSER_PROFILE = "openclaw"
STATE_FILE = Path.home() / ".openclaw/workspace/memory/weibo-state.json"

# Element references (may need updating)
MAIN_TEXTBOX_REF = "e136"
SEND_BUTTON_REF = "e194"
QUICK_POST_BUTTON_REF = "e75"
QUICK_TEXTBOX_REF = "e1028"
QUICK_SEND_REF = "e1086"


def read_state():
    """Read current state from state file."""
    if STATE_FILE.exists():
        with open(STATE_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    return {
        "lastPublishTime": 0,
        "lastPublishDate": None,
        "lastContent": None
    }


def write_state(content):
    """Update state file with new post info."""
    state = {
        "lastPublishTime": int(time.time()),
        "lastPublishDate": datetime.now().isoformat(),
        "lastContent": content
    }
    
    STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(STATE_FILE, 'w', encoding='utf-8') as f:
        json.dump(state, f, ensure_ascii=False, indent=2)


def check_rate_limit(min_interval=3600):
    """Check if enough time has passed since last post."""
    state = read_state()
    now = int(time.time())
    time_since_last = now - state["lastPublishTime"]
    
    if time_since_last < min_interval:
        remaining = min_interval - time_since_last
        print(f"⚠️  Rate limit: Please wait {remaining} seconds before posting again.")
        return False
    
    return True


def validate_content(content):
    """Validate content before posting."""
    if not content or not content.strip():
        print("❌ Error: Content cannot be empty.")
        return False
    
    if len(content) > 2000:
        print(f"❌ Error: Content too long ({len(content)} chars). Maximum is 2000.")
        return False
    
    return True


def post_to_weibo(content, use_quick_post=False):
    """
    Post content to Weibo using browser automation.
    
    This is a reference implementation showing the workflow.
    In practice, you would use OpenClaw's browser tool directly.
    
    Args:
        content: Text content to post
        use_quick_post: Use quick post popup instead of main textbox
    
    Returns:
        bool: True if successful, False otherwise
    """
    print(f"📝 Posting to Weibo...")
    print(f"Content: {content[:50]}{'...' if len(content) > 50 else ''}")
    print(f"Length: {len(content)} characters")
    
    # This is pseudocode - actual implementation uses OpenClaw browser tool
    steps = [
        f"1. Open {WEIBO_URL}",
        "2. Take snapshot to get element refs",
        "3. Click textbox",
        "4. Type content",
        "5. Click send button",
        "6. Verify post appeared"
    ]
    
    print("\nSteps:")
    for step in steps:
        print(f"  {step}")
    
    print("\n✅ Post workflow defined. Use OpenClaw browser tool to execute.")
    return True


def main():
    """Main entry point."""
    import argparse
    
    parser = argparse.ArgumentParser(description="Post to Weibo via browser automation")
    parser.add_argument("content", nargs="?", help="Content to post")
    parser.add_argument("--file", "-f", help="Read content from file")
    parser.add_argument("--interactive", "-i", action="store_true", help="Interactive mode")
    parser.add_argument("--quick", "-q", action="store_true", help="Use quick post popup")
    parser.add_argument("--no-rate-limit", action="store_true", help="Skip rate limit check")
    parser.add_argument("--state", action="store_true", help="Show current state")
    
    args = parser.parse_args()
    
    # Show state
    if args.state:
        state = read_state()
        print("Current state:")
        print(json.dumps(state, indent=2, ensure_ascii=False))
        return 0
    
    # Get content
    content = None
    
    if args.file:
        with open(args.file, 'r', encoding='utf-8') as f:
            content = f.read().strip()
    elif args.interactive:
        print("Enter content (Ctrl+D or Ctrl+Z to finish):")
        lines = []
        try:
            while True:
                line = input()
                lines.append(line)
        except EOFError:
            pass
        content = "\n".join(lines).strip()
    elif args.content:
        content = args.content
    else:
        parser.print_help()
        return 1
    
    # Validate
    if not validate_content(content):
        return 1
    
    # Check rate limit
    if not args.no_rate_limit and not check_rate_limit():
        return 1
    
    # Post
    success = post_to_weibo(content, use_quick_post=args.quick)
    
    if success:
        write_state(content)
        print("\n✅ Success! State updated.")
        return 0
    else:
        print("\n❌ Failed to post.")
        return 1


if __name__ == "__main__":
    sys.exit(main())


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)