mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-16 15:39:47 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5c54e26da | |||
| 2a0bba6161 | |||
| c44a524fa6 | |||
| 826535abe4 |
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||||
"version": "1.89.2"
|
"version": "1.90.1"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
English | [中文](./CHANGELOG.zh.md)
|
English | [中文](./CHANGELOG.zh.md)
|
||||||
|
|
||||||
|
## 1.90.1 - 2026-04-05
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- `baoyu-post-to-wechat`: detect actual image format from buffer magic bytes to fix CDN content-type mismatches (e.g. WebP served for .png URLs); treat WebP as PNG-preferred for transparency handling
|
||||||
|
|
||||||
## 1.89.1 - 2026-04-01
|
## 1.89.1 - 2026-04-01
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
[English](./CHANGELOG.md) | 中文
|
[English](./CHANGELOG.md) | 中文
|
||||||
|
|
||||||
|
## 1.90.1 - 2026-04-05
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- `baoyu-post-to-wechat`:通过 magic bytes 检测实际图片格式,修复 CDN 返回与 URL 扩展名不一致的 content-type 问题(如 .png URL 实际返回 WebP);WebP 格式按 PNG 策略处理以保留透明度
|
||||||
|
|
||||||
## 1.89.1 - 2026-04-01
|
## 1.89.1 - 2026-04-01
|
||||||
|
|
||||||
### 新功能
|
### 新功能
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.89.2**.
|
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.90.1**.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-1
|
|||||||
|
|
||||||
# Direct content input
|
# Direct content input
|
||||||
/baoyu-xhs-images 今日星座运势
|
/baoyu-xhs-images 今日星座运势
|
||||||
|
|
||||||
|
# Non-interactive (skip all confirmations, for scheduled tasks)
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes --preset knowledge-card
|
||||||
```
|
```
|
||||||
|
|
||||||
**Styles** (visual aesthetics): `cute` (default), `fresh`, `warm`, `bold`, `minimal`, `retro`, `pop`, `notion`, `chalkboard`
|
**Styles** (visual aesthetics): `cute` (default), `fresh`, `warm`, `bold`, `minimal`, `retro`, `pop`, `notion`, `chalkboard`
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ clawhub install baoyu-markdown-to-html
|
|||||||
|
|
||||||
# 直接输入内容
|
# 直接输入内容
|
||||||
/baoyu-xhs-images 今日星座运势
|
/baoyu-xhs-images 今日星座运势
|
||||||
|
|
||||||
|
# 非交互模式(跳过所有确认,适用于定时任务)
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes --preset knowledge-card
|
||||||
```
|
```
|
||||||
|
|
||||||
**风格**(视觉美学):`cute`(默认)、`fresh`、`warm`、`bold`、`minimal`、`retro`、`pop`、`notion`、`chalkboard`
|
**风格**(视觉美学):`cute`(默认)、`fresh`、`warm`、`bold`、`minimal`、`retro`、`pop`、`notion`、`chalkboard`
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
type WechatUploadAsset,
|
type WechatUploadAsset,
|
||||||
prepareWechatBodyImageUpload,
|
prepareWechatBodyImageUpload,
|
||||||
needsWechatBodyImageProcessing,
|
needsWechatBodyImageProcessing,
|
||||||
|
detectImageFormatFromBuffer,
|
||||||
} from "./wechat-image-processor.ts";
|
} from "./wechat-image-processor.ts";
|
||||||
|
|
||||||
interface AccessTokenResponse {
|
interface AccessTokenResponse {
|
||||||
@@ -138,6 +139,16 @@ async function loadUploadAsset(
|
|||||||
contentType = mimeTypes[fileExt] || "image/jpeg";
|
contentType = mimeTypes[fileExt] || "image/jpeg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect actual format from magic bytes to fix extension/content-type mismatches
|
||||||
|
// (e.g. CDNs serving WebP for URLs with .png extension)
|
||||||
|
const detected = detectImageFormatFromBuffer(fileBuffer);
|
||||||
|
if (detected && detected.contentType !== contentType) {
|
||||||
|
console.error(`[wechat-api] Format mismatch: ${filename} declared as ${contentType}, actual ${detected.contentType}`);
|
||||||
|
contentType = detected.contentType;
|
||||||
|
fileExt = detected.fileExt;
|
||||||
|
filename = `${path.basename(filename, path.extname(filename))}${detected.fileExt}`;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
buffer: fileBuffer,
|
buffer: fileBuffer,
|
||||||
filename,
|
filename,
|
||||||
|
|||||||
@@ -52,6 +52,39 @@ const MIME_TO_EXT: Record<string, string> = {
|
|||||||
const JPEG_QUALITY_STEPS = [82, 74, 66, 58, 50, 42, 34];
|
const JPEG_QUALITY_STEPS = [82, 74, 66, 58, 50, 42, 34];
|
||||||
const MAX_WIDTH_STEPS = [2560, 2048, 1600, 1280, 1024, 800, 640, 480];
|
const MAX_WIDTH_STEPS = [2560, 2048, 1600, 1280, 1024, 800, 640, 480];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect actual image format from buffer magic bytes.
|
||||||
|
* Returns corrected { contentType, fileExt } or null if unknown.
|
||||||
|
*/
|
||||||
|
export function detectImageFormatFromBuffer(buffer: Buffer): { contentType: string; fileExt: string } | null {
|
||||||
|
if (buffer.length < 12) return null;
|
||||||
|
|
||||||
|
// WebP: RIFF....WEBP
|
||||||
|
if (
|
||||||
|
buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 &&
|
||||||
|
buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50
|
||||||
|
) {
|
||||||
|
return { contentType: "image/webp", fileExt: ".webp" };
|
||||||
|
}
|
||||||
|
// PNG: 89 50 4E 47
|
||||||
|
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
|
||||||
|
return { contentType: "image/png", fileExt: ".png" };
|
||||||
|
}
|
||||||
|
// JPEG: FF D8 FF
|
||||||
|
if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
|
||||||
|
return { contentType: "image/jpeg", fileExt: ".jpg" };
|
||||||
|
}
|
||||||
|
// GIF: GIF8
|
||||||
|
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
|
||||||
|
return { contentType: "image/gif", fileExt: ".gif" };
|
||||||
|
}
|
||||||
|
// BMP: BM
|
||||||
|
if (buffer[0] === 0x42 && buffer[1] === 0x4d) {
|
||||||
|
return { contentType: "image/bmp", fileExt: ".bmp" };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let webpDecoderReady: Promise<void> | undefined;
|
let webpDecoderReady: Promise<void> | undefined;
|
||||||
|
|
||||||
type JimpImage = Awaited<ReturnType<typeof Jimp.read>>;
|
type JimpImage = Awaited<ReturnType<typeof Jimp.read>>;
|
||||||
@@ -209,7 +242,8 @@ export async function prepareWechatBodyImageUpload(
|
|||||||
|
|
||||||
const image = await loadImageForProcessing(asset);
|
const image = await loadImageForProcessing(asset);
|
||||||
const widths = buildCandidateWidths(image.bitmap.width);
|
const widths = buildCandidateWidths(image.bitmap.width);
|
||||||
const preferPng = imageHasTransparency(image) || ensureFileExt(asset) === ".png";
|
const ext = ensureFileExt(asset);
|
||||||
|
const preferPng = imageHasTransparency(image) || ext === ".png" || ext === ".webp";
|
||||||
const processingNotes = buildProcessingNotes(asset);
|
const processingNotes = buildProcessingNotes(asset);
|
||||||
|
|
||||||
for (const width of widths) {
|
for (const width of widths) {
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ Break down complex content into eye-catching infographic series for Xiaohongshu
|
|||||||
# Direct input with options
|
# Direct input with options
|
||||||
/baoyu-xhs-images --style bold --layout comparison
|
/baoyu-xhs-images --style bold --layout comparison
|
||||||
[paste content]
|
[paste content]
|
||||||
|
|
||||||
|
# Non-interactive (for scheduled tasks / automation)
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes
|
||||||
|
/baoyu-xhs-images posts/ai-future/article.md --yes --preset knowledge-card
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
@@ -48,6 +52,7 @@ Break down complex content into eye-catching infographic series for Xiaohongshu
|
|||||||
| `--style <name>` | Visual style (see Style Gallery) |
|
| `--style <name>` | Visual style (see Style Gallery) |
|
||||||
| `--layout <name>` | Information layout (see Layout Gallery) |
|
| `--layout <name>` | Information layout (see Layout Gallery) |
|
||||||
| `--preset <name>` | Style + layout shorthand (see [Style Presets](references/style-presets.md)) |
|
| `--preset <name>` | Style + layout shorthand (see [Style Presets](references/style-presets.md)) |
|
||||||
|
| `--yes` | Non-interactive mode: skip all confirmations. Uses EXTEND.md preferences if found, otherwise uses defaults (no watermark, auto style/layout). Auto-confirms recommended plan (Path A). Suitable for scheduled tasks and automation. |
|
||||||
|
|
||||||
## Two Dimensions
|
## Two Dimensions
|
||||||
|
|
||||||
@@ -237,11 +242,11 @@ Copy and track progress:
|
|||||||
|
|
||||||
```
|
```
|
||||||
XHS Infographic Progress:
|
XHS Infographic Progress:
|
||||||
- [ ] Step 0: Check preferences (EXTEND.md) ⛔ BLOCKING
|
- [ ] Step 0: Check preferences (EXTEND.md) ⛔ BLOCKING (--yes: use defaults if not found)
|
||||||
- [ ] Found → load preferences → continue
|
- [ ] Found → load preferences → continue
|
||||||
- [ ] Not found → run first-time setup → MUST complete before Step 1
|
- [ ] Not found → run first-time setup → MUST complete before Step 1 (--yes: skip setup, use defaults)
|
||||||
- [ ] Step 1: Analyze content → analysis.md
|
- [ ] Step 1: Analyze content → analysis.md
|
||||||
- [ ] Step 2: Smart Confirm ⚠️ REQUIRED
|
- [ ] Step 2: Smart Confirm ⚠️ REQUIRED (--yes: auto-confirm Path A)
|
||||||
- [ ] Path A: Quick confirm → generate recommended outline
|
- [ ] Path A: Quick confirm → generate recommended outline
|
||||||
- [ ] Path B: Customize → adjust then generate outline
|
- [ ] Path B: Customize → adjust then generate outline
|
||||||
- [ ] Path C: Detailed → 3 outlines → second confirm → generate outline
|
- [ ] Path C: Detailed → 3 outlines → second confirm → generate outline
|
||||||
@@ -252,26 +257,30 @@ XHS Infographic Progress:
|
|||||||
### Flow
|
### Flow
|
||||||
|
|
||||||
```
|
```
|
||||||
Input → [Step 0: Preferences] ─┬─ Found → Continue
|
Input → [--yes?] ─┬─ Yes → [Step 0: Load or defaults] → Analyze → Auto-confirm → Generate → Complete
|
||||||
│
|
│
|
||||||
└─ Not found → First-Time Setup ⛔ BLOCKING
|
└─ No → [Step 0: Preferences] ─┬─ Found → Continue
|
||||||
│
|
│
|
||||||
└─ Complete setup → Save EXTEND.md → Continue
|
└─ Not found → First-Time Setup ⛔ BLOCKING
|
||||||
│
|
│
|
||||||
┌───────────────────────────────────────────────────────────────────────────┘
|
└─ Complete setup → Save EXTEND.md → Continue
|
||||||
↓
|
│
|
||||||
Analyze → [Smart Confirm] ─┬─ Quick: confirm recommended → outline.md → Generate → Complete
|
┌─────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
│
|
↓
|
||||||
├─ Customize: adjust options → outline.md → Generate → Complete
|
Analyze → [Smart Confirm] ─┬─ Quick: confirm recommended → outline.md → Generate → Complete
|
||||||
│
|
│
|
||||||
└─ Detailed: 3 outlines → [Confirm 2] → outline.md → Generate → Complete
|
├─ Customize: adjust options → outline.md → Generate → Complete
|
||||||
|
│
|
||||||
|
└─ Detailed: 3 outlines → [Confirm 2] → outline.md → Generate → Complete
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
|
### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
|
||||||
|
|
||||||
**Purpose**: Load user preferences or run first-time setup.
|
**Purpose**: Load user preferences or run first-time setup.
|
||||||
|
|
||||||
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about style, do NOT ask about layout — ONLY complete the preferences setup first.
|
**`--yes` mode**: If EXTEND.md found → load it. If not found → use built-in defaults (no watermark, style/layout auto-select, language from content). Do NOT run first-time setup, do NOT create EXTEND.md, do NOT ask any questions. Proceed directly to Step 1.
|
||||||
|
|
||||||
|
**CRITICAL** (interactive mode only): If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about style, do NOT ask about layout — ONLY complete the preferences setup first.
|
||||||
|
|
||||||
Check EXTEND.md existence (priority order):
|
Check EXTEND.md existence (priority order):
|
||||||
|
|
||||||
@@ -340,7 +349,11 @@ Read source content, save it if needed, and perform deep analysis.
|
|||||||
|
|
||||||
### Step 2: Smart Confirm ⚠️
|
### Step 2: Smart Confirm ⚠️
|
||||||
|
|
||||||
**Purpose**: Present auto-recommended plan, let user confirm or adjust. **Do NOT skip.**
|
**Purpose**: Present auto-recommended plan, let user confirm or adjust.
|
||||||
|
|
||||||
|
**`--yes` mode**: Skip this entire step. Use auto-recommended strategy + style + layout from Step 1 analysis (or `--style`/`--layout`/`--preset` if provided). Generate outline directly using Path A logic → save to `outline.md` → proceed to Step 3. No AskUserQuestion calls.
|
||||||
|
|
||||||
|
**Interactive mode**: Do NOT skip.
|
||||||
|
|
||||||
**Auto-Recommendation Logic**:
|
**Auto-Recommendation Logic**:
|
||||||
1. Use Auto Selection table to match content signals → best strategy + style + layout
|
1. Use Auto Selection table to match content signals → best strategy + style + layout
|
||||||
@@ -491,7 +504,7 @@ Reference: `references/config/watermark-guide.md`
|
|||||||
|
|
||||||
**Image Generation Skill Selection**:
|
**Image Generation Skill Selection**:
|
||||||
- Check available image generation skills
|
- Check available image generation skills
|
||||||
- If multiple skills available, ask user preference
|
- If multiple skills available: ask user preference (interactive) or use first available skill (`--yes` mode)
|
||||||
|
|
||||||
**Session Management**:
|
**Session Management**:
|
||||||
If image generation skill supports `--sessionId`:
|
If image generation skill supports `--sessionId`:
|
||||||
|
|||||||
Reference in New Issue
Block a user