本技能是 的合并版,目标是让用户只需要 一次即可开始使用。 约束: - 所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 。 - 禁止在本仓库编写/维护发布编排脚本(如 );发布动作必须在会话中由 执行。 - 禁止使用 (旧通道禁用,统一使用 )。 - 所有敏感数据(cookies、导出文件、截图)只落地在本机 目录,不要粘贴到聊天里。 执行硬约束(稳定性): - 同一 session 禁止并发操作(串行执行),否则容易触发 假失败。 - 的 ref 会漂移:关键动作前后必须重抓 ,并用 做二次定位兜底。 - 扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。 安装 说明: 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 完成扫码与导出。 目录约定(本机) 建议在你运行命令的工作目录下准备: - :登录页二维码截图(PNG) - :导出的原始 cookies(JSON) - :归一化后的 cookies(JSON) - :导出数据(CSV/XLSX/截图) - :发布笔记用的图标/配图素材与来源记录 A. 登录(扫码)并保存 cookies 目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。 1. 用 打开登录页: - - 若默认展示「手机号/…

,\n '^#?(test|tag|demo|sample|xxx)

本技能是 的合并版,目标是让用户只需要 一次即可开始使用。 约束: - 所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 。 - 禁止在本仓库编写/维护发布编排脚本(如 );发布动作必须在会话中由 执行。 - 禁止使用 (旧通道禁用,统一使用 )。 - 所有敏感数据(cookies、导出文件、截图)只落地在本机 目录,不要粘贴到聊天里。 执行硬约束(稳定性): - 同一 session 禁止并发操作(串行执行),否则容易触发 假失败。 - 的 ref 会漂移:关键动作前后必须重抓 ,并用 做二次定位兜底。 - 扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。 安装 说明: 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 完成扫码与导出。 目录约定(本机) 建议在你运行命令的工作目录下准备: - :登录页二维码截图(PNG) - :导出的原始 cookies(JSON) - :归一化后的 cookies(JSON) - :导出数据(CSV/XLSX/截图) - :发布笔记用的图标/配图素材与来源记录 A. 登录(扫码)并保存 cookies 目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。 1. 用 打开登录页: - - 若默认展示「手机号/…

,\n ],\n },\n real_topics: {\n min_count: 3,\n max_count: 8,\n placeholder_patterns: [\n '^#?(标签|话题|测试|示例|模板)

本技能是 的合并版,目标是让用户只需要 一次即可开始使用。 约束: - 所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 。 - 禁止在本仓库编写/维护发布编排脚本(如 );发布动作必须在会话中由 执行。 - 禁止使用 (旧通道禁用,统一使用 )。 - 所有敏感数据(cookies、导出文件、截图)只落地在本机 目录,不要粘贴到聊天里。 执行硬约束(稳定性): - 同一 session 禁止并发操作(串行执行),否则容易触发 假失败。 - 的 ref 会漂移:关键动作前后必须重抓 ,并用 做二次定位兜底。 - 扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。 安装 说明: 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 完成扫码与导出。 目录约定(本机) 建议在你运行命令的工作目录下准备: - :登录页二维码截图(PNG) - :导出的原始 cookies(JSON) - :归一化后的 cookies(JSON) - :导出数据(CSV/XLSX/截图) - :发布笔记用的图标/配图素材与来源记录 A. 登录(扫码)并保存 cookies 目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。 1. 用 打开登录页: - - 若默认展示「手机号/…

,\n '^#?(test|tag|demo|sample|xxx)

本技能是 的合并版,目标是让用户只需要 一次即可开始使用。 约束: - 所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 。 - 禁止在本仓库编写/维护发布编排脚本(如 );发布动作必须在会话中由 执行。 - 禁止使用 (旧通道禁用,统一使用 )。 - 所有敏感数据(cookies、导出文件、截图)只落地在本机 目录,不要粘贴到聊天里。 执行硬约束(稳定性): - 同一 session 禁止并发操作(串行执行),否则容易触发 假失败。 - 的 ref 会漂移:关键动作前后必须重抓 ,并用 做二次定位兜底。 - 扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。 安装 说明: 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 完成扫码与导出。 目录约定(本机) 建议在你运行命令的工作目录下准备: - :登录页二维码截图(PNG) - :导出的原始 cookies(JSON) - :归一化后的 cookies(JSON) - :导出数据(CSV/XLSX/截图) - :发布笔记用的图标/配图素材与来源记录 A. 登录(扫码)并保存 cookies 目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。 1. 用 打开登录页: - - 若默认展示「手机号/…

,\n ],\n },\n tag_registry: {\n fresh_within_days: 7,\n required_platform: 'xiaohongshu',\n },\n source: {\n evidence_snippet_min_len: 16,\n evidence_snippet_max_len: 180,\n key_facts_min_count: 2,\n key_facts_max_count: 5,\n key_fact_min_len: 8,\n key_fact_max_len: 80,\n },\n media: {\n min_count: 1,\n screenshot_keywords: ['screenshot', 'screen_shot', 'xhs_login', 'login_qr', 'after_click'],\n ratio_target: 3 / 4,\n ratio_tolerance: 0.02,\n preferred_sizes: [{ width: 1242, height: 1660 }],\n max_detail_items: 12,\n },\n anti_ai: {\n template_phrases: [\n '总的来说',\n '综上所述',\n '不难看出',\n '值得注意的是',\n '随着人工智能的发展',\n '随着ai的发展',\n '未来可期',\n '首先',\n '其次',\n '最后',\n ],\n personal_voice_keywords: ['我', '我们', '我觉得', '我观察', '我测了', '我试了', '我踩坑', '我自己', '这周我'],\n week_keywords: ['这周', '本周', '今天', '昨日', '刚刚'],\n strict_min_digit_count: 2,\n strict_min_signal_count: 2,\n },\n link_detection: {\n blocked_tlds: ['com', 'cn', 'net', 'org', 'io', 'me', 'co', 'app', 'dev'],\n },\n hot_mode: {\n source_date_must_be_today: true,\n },\n};\n\nfunction todayISO() {\n const d = new Date();\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${y}-${m}-${day}`;\n}\n\nfunction isScreenshotLike(pathLike, keywords) {\n if (!pathLike) return false;\n const s = String(pathLike).toLowerCase();\n const words = pickArray(keywords).map((x) => str(x).toLowerCase()).filter(Boolean);\n return words.some((w) => s.includes(w));\n}\n\nfunction str(v) {\n return String(v || '').trim();\n}\n\nfunction isValidDateYYYYMMDD(v) {\n return /^\\d{4}-\\d{2}-\\d{2}$/.test(v);\n}\n\nfunction isHttpUrl(v) {\n return /^https?:\\/\\//i.test(v);\n}\n\nfunction pickArray(v) {\n return Array.isArray(v) ? v : [];\n}\n\nfunction hasLiteralBackslashN(body) {\n const s = String(body || '');\n return s.includes('\\\\n');\n}\n\nfunction hasSlashNToken(body) {\n const s = String(body || '');\n return /(^|\\s)\\/n(\\s|$)/.test(s);\n}\n\nfunction containsLinkLike(text, blockedTlds) {\n const s = String(text || '').trim();\n if (!s) return false;\n if (/https?:\\/\\//i.test(s)) return true;\n if (/www\\./i.test(s)) return true;\n const tlds = uniqueList(pickArray(blockedTlds).map((x) => str(x).toLowerCase()).filter(Boolean));\n if (!tlds.length) return false;\n const tldPattern = tlds.map((x) => x.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\{head-tags}')).join('|');\n if (!tldPattern) return false;\n // very rough domain detection; intentionally strict to avoid accidental bans\n const domainLike = new RegExp(`\\\\b[a-z0-9-]+\\\\.(${tldPattern})\\\\b`, 'i');\n if (domainLike.test(s)) return true;\n return false;\n}\n\nfunction normalizeTag(tag) {\n const v = str(tag);\n if (!v) return '';\n return v.startsWith('#') ? v : `#${v}`;\n}\n\nfunction uniqueList(items) {\n const out = [];\n const seen = new Set();\n for (const it of items) {\n const v = str(it);\n if (!v) continue;\n const k = v.toLowerCase();\n if (seen.has(k)) continue;\n seen.add(k);\n out.push(v);\n }\n return out;\n}\n\nfunction parseDateSafe(iso) {\n const s = str(iso);\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return null;\n const d = new Date(`${s}T00:00:00`);\n if (Number.isNaN(d.getTime())) return null;\n return d;\n}\n\nfunction toPositiveInt(value, fallback) {\n const n = Number(value);\n if (!Number.isFinite(n) || n \u003c= 0) return fallback;\n return Math.floor(n);\n}\n\nfunction parseToggle(value, fallback = true) {\n const s = String(value ?? '').trim().toLowerCase();\n if (!s) return fallback;\n if (['1', 'true', 'on', 'yes', 'y'].includes(s)) return true;\n if (['0', 'false', 'off', 'no', 'n'].includes(s)) return false;\n return fallback;\n}\n\nfunction toFiniteNumber(value, fallback) {\n const n = Number(value);\n if (!Number.isFinite(n)) return fallback;\n return n;\n}\n\nfunction isPlainObject(v) {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\nfunction deepMerge(base, override) {\n if (Array.isArray(base)) {\n return Array.isArray(override) ? override : [...base];\n }\n if (isPlainObject(base)) {\n const out = { ...base };\n if (isPlainObject(override)) {\n for (const key of Object.keys(override)) {\n if (Object.prototype.hasOwnProperty.call(base, key)) {\n out[key] = deepMerge(base[key], override[key]);\n } else {\n out[key] = override[key];\n }\n }\n }\n return out;\n }\n return override === undefined ? base : override;\n}\n\nfunction compileRegexList(patterns, fallbackPatterns = []) {\n const out = [];\n const input = pickArray(patterns);\n for (const raw of input) {\n const source = str(raw);\n if (!source) continue;\n try {\n out.push(new RegExp(source, 'i'));\n } catch {\n // Ignore invalid custom regex patterns; defaults still apply.\n }\n }\n if (out.length > 0 || input.length === 0) return out;\n if (!fallbackPatterns.length) return out;\n return compileRegexList(fallbackPatterns, []);\n}\n\nfunction hasAnyKeyword(text, keywords) {\n const s = String(text || '');\n if (!s) return false;\n const words = pickArray(keywords).map((x) => str(x)).filter(Boolean);\n return words.some((w) => s.includes(w));\n}\n\nasync function loadPolicy(filePath, { allowMissing = false } = {}) {\n const policyPath = str(filePath);\n if (!policyPath) {\n return { exists: false, path: null, overrides: {}, error: null };\n }\n try {\n const raw = await readFile(policyPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (!isPlainObject(parsed)) {\n throw new Error(`Policy file is not a JSON object: ${policyPath}`);\n }\n return { exists: true, path: policyPath, overrides: parsed, error: null };\n } catch (e) {\n const code = e?.code || '';\n if (allowMissing && code === 'ENOENT') {\n return { exists: false, path: policyPath, overrides: {}, error: null };\n }\n throw new Error(`Failed to load policy file \"${policyPath}\": ${e?.message || String(e)}`);\n }\n}\n\nfunction daysSince(isoDate) {\n const d = parseDateSafe(isoDate);\n if (!d) return null;\n const now = new Date();\n const nowAtDay = new Date(`${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}T00:00:00`);\n const diff = nowAtDay.getTime() - d.getTime();\n return Math.floor(diff / (24 * 60 * 60 * 1000));\n}\n\nasync function loadTagRegistry(filePath) {\n try {\n const raw = await readFile(filePath, 'utf8');\n const data = JSON.parse(raw);\n const tagsRaw = Array.isArray(data)\n ? data\n : Array.isArray(data?.tags)\n ? data.tags\n : [];\n const normalized = uniqueList(tagsRaw.map(normalizeTag).filter(Boolean));\n return {\n exists: true,\n path: filePath,\n updated_at: str(data?.updated_at) || null,\n source: data?.source && typeof data.source === 'object' ? data.source : null,\n tags: normalized,\n };\n } catch {\n return {\n exists: false,\n path: filePath,\n updated_at: null,\n source: null,\n tags: [],\n };\n }\n}\n\nfunction hasAiTemplateStyle(body, phrases) {\n const s = String(body || '').toLowerCase();\n const templates = pickArray(phrases).map((x) => str(x)).filter(Boolean);\n return templates.filter((p) => s.includes(p.toLowerCase()));\n}\n\nfunction hasPersonalVoice(body, keywords) {\n return hasAnyKeyword(body, keywords);\n}\n\nfunction hasConcreteSignals({ body, sourceName, sourceDate, strictAntiAi, policy }) {\n const s = String(body || '');\n const minDigitCount = toPositiveInt(policy?.anti_ai?.strict_min_digit_count, 2);\n const minSignalCount = toPositiveInt(policy?.anti_ai?.strict_min_signal_count, 2);\n const weekKeywords = pickArray(policy?.anti_ai?.week_keywords);\n const digitCount = (s.match(/\\d/g) || []).length;\n const hasDateLike = /\\d{4}[年\\-/.]\\d{1,2}[月\\-/.]\\d{1,2}日?/.test(s) || /\\d{1,2}月\\d{1,2}日/.test(s);\n const hasAmountLike = /\\d+\\s*(亿|万|%|美元|人民币|条|家|款|次)/.test(s);\n const hasSourceMention = !!sourceName && s.includes(sourceName);\n const hasWeekMention = hasAnyKeyword(s, weekKeywords) || (!!sourceDate && s.includes(sourceDate));\n const hasHardFactSignal = digitCount >= minDigitCount || hasDateLike || hasAmountLike;\n const signalCount = [digitCount >= minDigitCount, hasDateLike, hasAmountLike, hasSourceMention, hasWeekMention].filter(Boolean).length;\n return {\n ok: strictAntiAi ? hasSourceMention && hasHardFactSignal && signalCount >= minSignalCount : signalCount >= 1,\n value: {\n digit_count: digitCount,\n min_digit_count: minDigitCount,\n has_date_like: hasDateLike,\n has_amount_like: hasAmountLike,\n has_source_mention: hasSourceMention,\n has_week_mention: hasWeekMention,\n has_hard_fact_signal: hasHardFactSignal,\n signal_count: signalCount,\n strict_min_signal_count: minSignalCount,\n strict_anti_ai: strictAntiAi,\n },\n };\n}\n\nfunction hasPlaceholderTag(tags, compiledPatterns) {\n const hit = [];\n for (const t of tags) {\n const x = str(t);\n if (!x) continue;\n if (compiledPatterns.some((re) => re.test(x))) hit.push(x);\n }\n return hit;\n}\n\nfunction isImagePath(p) {\n const s = String(p || '').toLowerCase();\n return s.endsWith('.png') || s.endsWith('.jpg') || s.endsWith('.jpeg');\n}\n\nasync function checkMediaDims(media, policy) {\n const images = media.filter(isImagePath);\n const results = [];\n for (const p of images) {\n try {\n const { width, height, format } = await getImageSize(p);\n const ratio = width / height;\n results.push({ path: p, ok: true, width, height, ratio, format });\n } catch (e) {\n results.push({ path: p, ok: false, error: e?.message || String(e) });\n }\n }\n\n // Strict-ish: expect portrait 3:4 assets for XHS cards (prefer 1242x1660).\n const ratioTarget = toFiniteNumber(policy?.media?.ratio_target, 3 / 4);\n const ratioTol = toFiniteNumber(policy?.media?.ratio_tolerance, 0.02);\n const preferredSizes = pickArray(policy?.media?.preferred_sizes);\n const maxDetailItems = toPositiveInt(policy?.media?.max_detail_items, 12);\n const bad = results.filter((r) => r.ok && Math.abs(r.ratio - ratioTarget) > ratioTol);\n const parseFailed = results.filter((r) => !r.ok);\n\n const hasAny = images.length > 0;\n const ok = !hasAny || (bad.length === 0 && parseFailed.length === 0);\n\n const perfect = results.filter((r) =>\n r.ok &&\n preferredSizes.some((s) => r.width === toPositiveInt(s?.width, -1) && r.height === toPositiveInt(s?.height, -1))\n );\n return {\n ok,\n value: {\n checked_images: images.length,\n passed: results.filter((r) => r.ok).length,\n parse_failed: parseFailed.length,\n ratio_bad: bad.length,\n perfect_1242x1660: perfect.length,\n preferred_size_matched: perfect.length,\n details: results.slice(0, maxDetailItems), // keep output bounded\n },\n };\n}\n\nasync function buildChecks(payload, mode, { policy, tagRegistry, allowUnverifiedTags, minRegistryTags, requireSourceEvidence, strictAntiAi }) {\n const topic = str(payload?.topic);\n const sourceName = str(payload?.source?.name);\n const sourceUrl = str(payload?.source?.url);\n const sourceDate = str(payload?.source?.date);\n const sourceEvidenceSnippet = str(payload?.source?.evidence_snippet);\n const sourceKeyFacts = uniqueList(pickArray(payload?.source?.key_facts).map((x) => str(x)).filter(Boolean));\n\n const title = str(payload?.post?.title);\n const body = str(payload?.post?.body);\n const tagsRaw = pickArray(payload?.post?.tags).map((x) => normalizeTag(x)).filter(Boolean);\n const tags = tagsRaw.filter((x) => x.startsWith('#'));\n const realTopicsRaw = pickArray(payload?.post?.real_topics).map((x) => normalizeTag(x)).filter(Boolean);\n const realTopics = realTopicsRaw.filter((x) => x.startsWith('#'));\n const media = pickArray(payload?.post?.media).map((x) => str(x)).filter(Boolean);\n\n const topicMinLen = toPositiveInt(policy?.topic?.min_len, 4);\n const titleMinLen = toPositiveInt(policy?.post?.title_min_len, 8);\n const titleMaxLen = Math.max(titleMinLen, toPositiveInt(policy?.post?.title_max_len, 20));\n const bodyMinLen = toPositiveInt(policy?.post?.body_min_len, 80);\n const tagMinCount = toPositiveInt(policy?.tags?.min_count, 3);\n const tagMaxCount = Math.max(tagMinCount, toPositiveInt(policy?.tags?.max_count, 8));\n const realTopicMinCount = toPositiveInt(policy?.real_topics?.min_count, 3);\n const realTopicMaxCount = Math.max(realTopicMinCount, toPositiveInt(policy?.real_topics?.max_count, 8));\n const registryFreshWithinDays = toPositiveInt(policy?.tag_registry?.fresh_within_days, 7);\n const requiredRegistryPlatform = str(policy?.tag_registry?.required_platform || 'xiaohongshu').toLowerCase();\n const sourceEvidenceMinLen = toPositiveInt(policy?.source?.evidence_snippet_min_len, 16);\n const sourceEvidenceMaxLen = Math.max(sourceEvidenceMinLen, toPositiveInt(policy?.source?.evidence_snippet_max_len, 180));\n const keyFactMinCount = toPositiveInt(policy?.source?.key_facts_min_count, 2);\n const keyFactMaxCount = Math.max(keyFactMinCount, toPositiveInt(policy?.source?.key_facts_max_count, 5));\n const keyFactMinLen = toPositiveInt(policy?.source?.key_fact_min_len, 8);\n const keyFactMaxLen = Math.max(keyFactMinLen, toPositiveInt(policy?.source?.key_fact_max_len, 80));\n const mediaMinCount = toPositiveInt(policy?.media?.min_count, 1);\n const screenshotKeywords = pickArray(policy?.media?.screenshot_keywords);\n const blockedTlds = pickArray(policy?.link_detection?.blocked_tlds);\n const tagPlaceholderPatterns = compileRegexList(policy?.tags?.placeholder_patterns, DEFAULT_POLICY.tags.placeholder_patterns);\n const realTopicPlaceholderPatterns = compileRegexList(policy?.real_topics?.placeholder_patterns, DEFAULT_POLICY.real_topics.placeholder_patterns);\n const hotSourceDateMustBeToday = parseToggle(policy?.hot_mode?.source_date_must_be_today, true);\n\n const titleLen = [...title].length;\n const bodyLen = [...body].length;\n const screenshotOnly = media.length > 0 && media.every((x) => isScreenshotLike(x, screenshotKeywords));\n const hotMode = mode === 'hot';\n const hasBackslashN = hasLiteralBackslashN(body);\n const hasSlashN = hasSlashNToken(body);\n const mediaDims = await checkMediaDims(media, policy);\n const linkInTitle = containsLinkLike(title, blockedTlds);\n const linkInBody = containsLinkLike(body, blockedTlds);\n const linkInTags = tagsRaw.some((t) => containsLinkLike(t, blockedTlds));\n const linkInMediaPath = media.some((p) => containsLinkLike(p, blockedTlds) || String(p).includes('://'));\n const duplicateTagCount = tagsRaw.length - uniqueList(tagsRaw).length;\n const duplicateRealTopicCount = realTopicsRaw.length - uniqueList(realTopicsRaw).length;\n const placeholderTags = hasPlaceholderTag(tagsRaw, tagPlaceholderPatterns);\n const placeholderRealTopics = hasPlaceholderTag(realTopicsRaw, realTopicPlaceholderPatterns);\n const aiTemplateHits = hasAiTemplateStyle(body, policy?.anti_ai?.template_phrases);\n const personalVoice = hasPersonalVoice(body, policy?.anti_ai?.personal_voice_keywords);\n const concreteSignals = hasConcreteSignals({ body, sourceName, sourceDate, strictAntiAi, policy });\n const registryTagSet = new Set((tagRegistry?.tags || []).map((x) => str(x).toLowerCase()));\n const unverifiedTags = tags.filter((t) => !registryTagSet.has(str(t).toLowerCase()));\n const unverifiedRealTopics = realTopics.filter((t) => !registryTagSet.has(str(t).toLowerCase()));\n const registryAgeDays = daysSince(tagRegistry?.updated_at);\n const registryFresh = registryAgeDays !== null && registryAgeDays >= 0 && registryAgeDays \u003c= registryFreshWithinDays;\n const registrySourcePlatform = str(tagRegistry?.source?.platform).toLowerCase();\n const registrySourceMethod = str(tagRegistry?.source?.method);\n\n const sourceEvidenceOk =\n !requireSourceEvidence ||\n (sourceEvidenceSnippet.length >= sourceEvidenceMinLen &&\n sourceEvidenceSnippet.length \u003c= sourceEvidenceMaxLen &&\n !containsLinkLike(sourceEvidenceSnippet, blockedTlds) &&\n (!!sourceName && sourceEvidenceSnippet.includes(sourceName)));\n\n const sourceKeyFactLengthBad = sourceKeyFacts.filter((x) => x.length \u003c keyFactMinLen || x.length > keyFactMaxLen);\n const sourceKeyFactLinkBad = sourceKeyFacts.filter((x) => containsLinkLike(x, blockedTlds));\n const sourceKeyFactHasDateOrNumber = sourceKeyFacts.some(\n (x) => /\\d/.test(x) || /\\d{4}[年\\-/.]\\d{1,2}[月\\-/.]\\d{1,2}日?/.test(x) || /\\d{1,2}月\\d{1,2}日/.test(x)\n );\n const sourceKeyFactsOk =\n !requireSourceEvidence ||\n (sourceKeyFacts.length >= keyFactMinCount &&\n sourceKeyFacts.length \u003c= keyFactMaxCount &&\n sourceKeyFactLengthBad.length === 0 &&\n sourceKeyFactLinkBad.length === 0 &&\n sourceKeyFactHasDateOrNumber);\n\n const checks = {\n has_topic: {\n ok: topic.length >= topicMinLen,\n value: topic || null,\n },\n has_source: {\n ok: !!sourceName && isHttpUrl(sourceUrl) && isValidDateYYYYMMDD(sourceDate),\n value: { name: sourceName || null, url: sourceUrl || null, date: sourceDate || null },\n },\n source_evidence_snippet_ok: {\n ok: sourceEvidenceOk,\n value: {\n required: requireSourceEvidence,\n min_len: sourceEvidenceMinLen,\n max_len: sourceEvidenceMaxLen,\n length: sourceEvidenceSnippet.length,\n contains_source_name: !!sourceName && sourceEvidenceSnippet.includes(sourceName),\n },\n },\n source_key_facts_ok: {\n ok: sourceKeyFactsOk,\n value: {\n required: requireSourceEvidence,\n min_count: keyFactMinCount,\n max_count: keyFactMaxCount,\n min_len: keyFactMinLen,\n max_len: keyFactMaxLen,\n count: sourceKeyFacts.length,\n bad_length: sourceKeyFactLengthBad,\n has_link_like: sourceKeyFactLinkBad,\n has_date_or_number_signal: sourceKeyFactHasDateOrNumber,\n },\n },\n title_ok: {\n ok: titleLen >= titleMinLen && titleLen \u003c= titleMaxLen,\n value: { title: title || null, length: titleLen, min_len: titleMinLen, max_len: titleMaxLen },\n },\n body_ok: {\n ok: bodyLen >= bodyMinLen,\n value: { length: bodyLen, min_len: bodyMinLen },\n },\n body_newline_normalized: {\n // Allow literal \"\\\\n\" in payload (we can normalize before writing), but forbid \"/n\" token.\n ok: !hasSlashN,\n value: {\n has_literal_backslash_n: hasBackslashN,\n has_slash_n_token: hasSlashN,\n },\n },\n tags_ok: {\n ok: tags.length >= tagMinCount && tags.length \u003c= tagMaxCount && duplicateTagCount === 0,\n value: { count: tags.length, min_count: tagMinCount, max_count: tagMaxCount, duplicate_count: duplicateTagCount, tags },\n },\n tags_not_placeholder: {\n ok: placeholderTags.length === 0,\n value: {\n hit: placeholderTags,\n },\n },\n real_topics_ok: {\n ok: realTopics.length >= realTopicMinCount && realTopics.length \u003c= realTopicMaxCount && duplicateRealTopicCount === 0,\n value: {\n count: realTopics.length,\n min_count: realTopicMinCount,\n max_count: realTopicMaxCount,\n duplicate_count: duplicateRealTopicCount,\n real_topics: realTopics,\n },\n },\n real_topics_not_placeholder: {\n ok: placeholderRealTopics.length === 0,\n value: {\n hit: placeholderRealTopics,\n },\n },\n tag_registry_meta_ok: {\n ok:\n tagRegistry.exists &&\n registryFresh &&\n tagRegistry.tags.length >= minRegistryTags &&\n registrySourcePlatform === requiredRegistryPlatform &&\n !!registrySourceMethod,\n value: {\n registry_exists: !!tagRegistry.exists,\n registry_path: tagRegistry.path,\n registry_updated_at: tagRegistry.updated_at,\n registry_age_days: registryAgeDays,\n registry_fresh: registryFresh,\n registry_fresh_within_days: registryFreshWithinDays,\n registry_fresh_within_days_7: registryFresh,\n registry_tag_count: tagRegistry.tags.length,\n min_registry_tags: minRegistryTags,\n source_platform: registrySourcePlatform || null,\n required_source_platform: requiredRegistryPlatform || null,\n source_method: registrySourceMethod || null,\n },\n },\n tags_from_registry: {\n ok: allowUnverifiedTags || (tagRegistry.exists && registryFresh && unverifiedTags.length === 0),\n value: {\n allow_unverified_tags: allowUnverifiedTags,\n registry_exists: !!tagRegistry.exists,\n registry_path: tagRegistry.path,\n registry_updated_at: tagRegistry.updated_at,\n registry_age_days: registryAgeDays,\n registry_fresh: registryFresh,\n registry_fresh_within_days: registryFreshWithinDays,\n registry_fresh_within_days_7: registryFresh,\n registry_tag_count: tagRegistry.tags.length,\n unverified_tags: unverifiedTags,\n },\n },\n real_topics_from_registry: {\n ok: allowUnverifiedTags || (tagRegistry.exists && registryFresh && unverifiedRealTopics.length === 0),\n value: {\n allow_unverified_tags: allowUnverifiedTags,\n registry_exists: !!tagRegistry.exists,\n registry_path: tagRegistry.path,\n registry_updated_at: tagRegistry.updated_at,\n registry_age_days: registryAgeDays,\n registry_fresh: registryFresh,\n registry_fresh_within_days: registryFreshWithinDays,\n registry_fresh_within_days_7: registryFresh,\n registry_tag_count: tagRegistry.tags.length,\n unverified_real_topics: unverifiedRealTopics,\n },\n },\n no_links_in_content: {\n ok: !(linkInTitle || linkInBody || linkInTags),\n value: {\n title: linkInTitle,\n body: linkInBody,\n tags: linkInTags,\n },\n },\n no_links_in_media_path: {\n ok: !linkInMediaPath,\n value: linkInMediaPath ? media : null,\n },\n media_ok: {\n ok: media.length >= mediaMinCount && !screenshotOnly,\n value: { count: media.length, min_count: mediaMinCount, screenshot_only: screenshotOnly, media },\n },\n media_dim_ok: mediaDims,\n anti_ai_personal_voice: {\n ok: personalVoice,\n value: { has_personal_voice: personalVoice },\n },\n anti_ai_concrete_signals: concreteSignals,\n anti_ai_source_mentioned_in_body: {\n ok: !!sourceName && body.includes(sourceName),\n value: {\n source_name: sourceName || null,\n mentioned: !!sourceName && body.includes(sourceName),\n },\n },\n anti_ai_template_phrase: {\n ok: aiTemplateHits.length === 0,\n value: {\n hit: aiTemplateHits,\n },\n },\n hot_source_is_today: {\n ok: !hotMode || !hotSourceDateMustBeToday || sourceDate === todayISO(),\n value: {\n source_date_must_be_today: hotSourceDateMustBeToday,\n required_date: hotMode && hotSourceDateMustBeToday ? todayISO() : null,\n source_date: sourceDate || null,\n },\n },\n };\n\n return checks;\n}\n\nasync function main(argv) {\n const { values } = parseArgs({\n args: argv,\n options: {\n in: { type: 'string' },\n mode: { type: 'string', default: 'normal' },\n policy: { type: 'string', default: DEFAULT_POLICY_PATH },\n 'tag-registry': { type: 'string', default: './data/tag_registry.json' },\n 'allow-unverified-tags': { type: 'boolean', default: false },\n 'min-registry-tags': { type: 'string', default: '12' },\n 'require-source-evidence': { type: 'string', default: 'on' },\n 'strict-anti-ai': { type: 'string', default: 'on' },\n json: { type: 'boolean', default: true },\n help: { type: 'boolean', default: false },\n },\n allowPositionals: true,\n });\n\n if (values.help) {\n console.log(usage());\n return;\n }\n\n if (!values.in) {\n throw new Error('Missing --in \u003cpayloadJsonPath>');\n }\n\n const raw = await readFile(values.in, 'utf8');\n const payload = JSON.parse(raw);\n const mode = str(values.mode || 'normal').toLowerCase();\n const policyFilePath = str(values.policy) || DEFAULT_POLICY_PATH;\n const customPolicy = await loadPolicy(policyFilePath, { allowMissing: false });\n const effectivePolicy = deepMerge(DEFAULT_POLICY, customPolicy.overrides || {});\n const tagRegistryPath = str(values['tag-registry']) || './data/tag_registry.json';\n const tagRegistry = await loadTagRegistry(tagRegistryPath);\n const allowUnverifiedTags = !!values['allow-unverified-tags'];\n const minRegistryTags = toPositiveInt(values['min-registry-tags'], 12);\n const requireSourceEvidence = parseToggle(values['require-source-evidence'], true);\n const strictAntiAi = parseToggle(values['strict-anti-ai'], true);\n const checks = await buildChecks(payload, mode, {\n policy: effectivePolicy,\n tagRegistry,\n allowUnverifiedTags,\n minRegistryTags,\n requireSourceEvidence,\n strictAntiAi,\n });\n\n const missing = Object.entries(checks)\n .filter(([, item]) => !item.ok)\n .map(([key]) => key);\n\n const result = {\n task: 'xhs_publish_payload_validate',\n ok: missing.length === 0,\n mode,\n policy: {\n policy_path: customPolicy.path,\n policy_loaded: customPolicy.exists,\n tag_registry_path: tagRegistry.path,\n allow_unverified_tags: allowUnverifiedTags,\n min_registry_tags: minRegistryTags,\n require_source_evidence: requireSourceEvidence,\n anti_ai_style_required: true,\n strict_anti_ai: strictAntiAi,\n policy_snapshot: effectivePolicy,\n },\n checks,\n missing,\n };\n\n if (values.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`ok: ${result.ok}`);\n console.log(`missing: ${missing.join(', ') || '(none)'}`);\n }\n\n if (!result.ok) {\n process.exitCode = 2;\n }\n}\n\nmain(process.argv.slice(2)).catch((e) => {\n console.error(e?.message || String(e));\n process.exitCode = 1;\n});\n","content_type":"text/javascript","language":"javascript","size":27703,"content_sha256":"3cbb121790f6ecc39248036c74bfde5d97946986cb55a87191536b8f27d3db8a"}],"content_json":{"type":"doc","content":[{"type":"paragraph","content":[{"text":"本技能是 ","type":"text"},{"text":"xhs-*","type":"text","marks":[{"type":"code_inline"}]},{"text":" 的合并版,目标是让用户只需要 ","type":"text"},{"text":"clawhub install xhs-skill","type":"text","marks":[{"type":"code_inline"}]},{"text":" 一次即可开始使用。","type":"text"}]},{"type":"paragraph","content":[{"text":"约束:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止在本仓库编写/维护发布编排脚本(如 ","type":"text"},{"text":"publish_from_payload","type":"text","marks":[{"type":"code_inline"}]},{"text":");发布动作必须在会话中由 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 执行。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止使用 ","type":"text"},{"text":"agent-browser","type":"text","marks":[{"type":"code_inline"}]},{"text":"(旧通道禁用,统一使用 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"所有敏感数据(cookies、导出文件、截图)只落地在本机 ","type":"text"},{"text":"data/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 目录,不要粘贴到聊天里。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"执行硬约束(稳定性):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"同一 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" session 禁止并发操作(串行执行),否则容易触发 ","type":"text"},{"text":"os error 35","type":"text","marks":[{"type":"code_inline"}]},{"text":" 假失败。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"snapshot","type":"text","marks":[{"type":"code_inline"}]},{"text":" 的 ref 会漂移:关键动作前后必须重抓 ","type":"text"},{"text":"snapshot -i","type":"text","marks":[{"type":"code_inline"}]},{"text":",并用 ","type":"text"},{"text":"placeholder/role/text","type":"text","marks":[{"type":"code_inline"}]},{"text":" 做二次定位兜底。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"安装","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"clawhub install xhs-skill\ncd skills/xhs-skill\nnpm i","type":"text"}]},{"type":"paragraph","content":[{"text":"说明:","type":"text"},{"text":"npm i","type":"text","marks":[{"type":"code_inline"}]},{"text":" 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 完成扫码与导出。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"目录约定(本机)","type":"text"}]},{"type":"paragraph","content":[{"text":"建议在你运行命令的工作目录下准备:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"data/xhs_login_qr.png","type":"text","marks":[{"type":"code_inline"}]},{"text":":登录页二维码截图(PNG)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"data/raw_cookies.json","type":"text","marks":[{"type":"code_inline"}]},{"text":":导出的原始 cookies(JSON)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"data/xhs_cookies.json","type":"text","marks":[{"type":"code_inline"}]},{"text":":归一化后的 cookies(JSON)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"data/exports/\u003cYYYY-MM-DD>/","type":"text","marks":[{"type":"code_inline"}]},{"text":":导出数据(CSV/XLSX/截图)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"data/assets/\u003cYYYY-MM-DD>/","type":"text","marks":[{"type":"code_inline"}]},{"text":":发布笔记用的图标/配图素材与来源记录","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"mkdir -p data","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"A. 登录(扫码)并保存 cookies","type":"text"}]},{"type":"paragraph","content":[{"text":"目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"用 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 打开登录页:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"https://creator.xiaohongshu.com/login","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若默认展示「手机号/验证码登录」,点击「扫码」切换到二维码视图","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"让 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 截图保存二维码(PNG)到 ","type":"text"},{"text":"data/xhs_login_qr.png","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"(可选)用本地 CLI 解码二维码文本并打印 ASCII 二维码:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node ./bin/xhs-skill.mjs qr show --in ./data/xhs_login_qr.png","type":"text"}]},{"type":"paragraph","content":[{"text":"OpenClaw 回传规范(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止只回传文件路径(例如仅说 ","type":"text"},{"text":"data/xhs_login_qr.png","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"必须先执行 ","type":"text"},{"text":"node ./bin/xhs-skill.mjs qr show --in ./data/xhs_login_qr.png","type":"text","marks":[{"type":"code_inline"}]},{"text":",然后把输出的二维码文本 + ASCII 二维码直接发给用户。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若会话支持图片渲染,再附上二维码截图绝对路径(或图片附件)作为补充。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发完二维码后必须暂停,等待用户确认“已扫码”再继续 cookies 导出。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"推荐回传模板:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"请用小红书 App 扫这个二维码登录。\n二维码文本: \u003cqr_text>\n\u003cASCII QR>","type":"text"}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"用小红书 App 扫码完成登录后,导出 cookies 到 ","type":"text"},{"text":"data/raw_cookies.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"(不走 DevTools):","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"agent-browser-stealth cookies --json > ./data/raw_cookies.json","type":"text"}]},{"type":"ordered_list","attrs":{"order":5,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"归一化 cookies 并保存到 ","type":"text"},{"text":"data/xhs_cookies.json","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node ./bin/xhs-skill.mjs cookies normalize --in ./data/raw_cookies.json --out ./data/xhs_cookies.json\nnode ./bin/xhs-skill.mjs cookies status --in ./data/xhs_cookies.json","type":"text"}]},{"type":"paragraph","content":[{"text":"5.1 推荐用脚本做后验校验(可执行门禁):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 例:先让 agent-browser-stealth 记录当前 URL 与后台探测后的 URL\nCURRENT_URL=\"$(agent-browser-stealth get url)\"\nagent-browser-stealth open https://creator.xiaohongshu.com/creator/home\nPROBE_FINAL_URL=\"$(agent-browser-stealth get url)\"\n\nnode ./scripts/verify_login.mjs \\\n --cookies ./data/xhs_cookies.json \\\n --current-url \"$CURRENT_URL\" \\\n --probe-final-url \"$PROBE_FINAL_URL\" \\\n --json","type":"text"}]},{"type":"paragraph","content":[{"text":"登录成功判定(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"必须同时满足以下 2 条才可回报“登录完成”(","type":"text"},{"text":"web_session","type":"text","marks":[{"type":"code_inline"}]},{"text":" 不再作为硬依赖):","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"当前 URL 已离开 ","type":"text"},{"text":"/login","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"可访问创作者后台页面,且不会 401/回跳登录","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"加分项:cookies 中存在“session-like cookie”(例如 ","type":"text"},{"text":"web_session","type":"text","marks":[{"type":"code_inline"}]},{"text":",或 cookie 名含 ","type":"text"},{"text":"session","type":"text","marks":[{"type":"code_inline"}]},{"text":")。没有也可能可用,但稳定性更差。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"任一强制条件不满足,必须回报“登录失败/未完成”,并重试登录流程;禁止误报成功。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"登录结果输出契约(JSON):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"task\": \"xhs_login\",\n \"ok\": true,\n \"checks\": {\n \"left_login\": true,\n \"backend_not_rejected\": true,\n \"has_session_like_cookie\": true\n },\n \"artifacts\": {\n \"qr_png\": \"data/xhs_login_qr.png\",\n \"raw_cookies\": \"data/raw_cookies.json\",\n \"normalized_cookies\": \"data/xhs_cookies.json\"\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"失败时 ","type":"text"},{"text":"ok=false","type":"text","marks":[{"type":"code_inline"}]},{"text":",并给出失败项(例如仍在 ","type":"text"},{"text":"/login","type":"text","marks":[{"type":"code_inline"}]},{"text":"、或 probe 回跳),禁止输出“已完成”。","type":"text"}]},{"type":"ordered_list","attrs":{"order":6,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"(可选)生成 ","type":"text"},{"text":"Cookie:","type":"text","marks":[{"type":"code_inline"}]},{"text":" header:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node ./bin/xhs-skill.mjs cookies to-header --in ./data/xhs_cookies.json","type":"text"}]},{"type":"paragraph","content":[{"text":"失败回退:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"二维码解码失败:通常是没有切到扫码视图或二维码太小,让 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 放大后重新截图(仍为 PNG)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"cookies 归一化失败:保留原始 ","type":"text"},{"text":"data/raw_cookies.json","type":"text","marks":[{"type":"code_inline"}]},{"text":",后续再扩展兼容分支。","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"A1. 防封/限流运行规范(强制)","type":"text"}]},{"type":"paragraph","content":[{"text":"核心结论:小红书风控主要看“节奏 + 指纹 + 行为 + IP + 账号权重”。工具本身不是主因,使用方式才是主因。","type":"text"}]},{"type":"paragraph","content":[{"text":"强制策略:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"真人节奏:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止连续无停顿点击/填写;关键动作之间必须随机停顿(建议 ","type":"text"},{"text":"1.2s~7s","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"输入优先 ","type":"text"},{"text":"type --delay","type":"text","marks":[{"type":"code_inline"}]},{"text":"(逐字),避免全量瞬时 ","type":"text"},{"text":"fill","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"固定指纹:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"运行发布流程时优先固定 ","type":"text"},{"text":"--profile","type":"text","marks":[{"type":"code_inline"}]},{"text":",并启用 ","type":"text"},{"text":"--headed","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"推荐同一账号长期复用同一个 profile 目录,不要每次新建临时环境。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":3,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布频率门禁:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"同一 profile 默认 ","type":"text"},{"text":"24h \u003c= 3","type":"text","marks":[{"type":"code_inline"}]},{"text":" 篇。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"两次发布最小间隔默认 ","type":"text"},{"text":"30","type":"text","marks":[{"type":"code_inline"}]},{"text":" 分钟。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"命中门禁必须中止,不允许强发。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布前预热行为:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"先做一次短时正常浏览(首页/创作者后台停留 + 滚动),再进入发布页。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止“打开页面后立刻提交”。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":5,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"网络与设备:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止机房 IP / 高频切换代理。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"优先家庭网络或手机热点;同账号尽量保持设备/IP 稳定。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":6,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"被限流后的处理:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"限流:停自动化,回归手动正常使用 ","type":"text"},{"text":"3~7","type":"text","marks":[{"type":"code_inline"}]},{"text":" 天。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"封号:仅能申诉;换号时要同时更换 ","type":"text"},{"text":"profile + IP + 设备环境","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"B. 发布笔记(图文/视频)","type":"text"}]},{"type":"paragraph","content":[{"text":"输入(用户提供):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"笔记类型:图文 或 视频","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题、正文、标签(必填)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"话题(必填;做热点发布时必须是“今天热点”)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"图片/视频路径(本机绝对路径优先)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"图标/配图需求(可选):关键词、风格(扁平/拟物/线性)、主色、是否透明背景","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"热点来源(必填):来源名、来源 URL、来源日期(","type":"text"},{"text":"YYYY-MM-DD","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"发布硬门禁(强制):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"先把发布素材整理为 ","type":"text"},{"text":"data/publish_payload.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"(示例):","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"topic\": \"今日热点:xxxx\",\n \"source\": {\n \"name\": \"央视新闻\",\n \"url\": \"https://example.com/news\",\n \"date\": \"2026-02-12\",\n \"evidence_snippet\": \"2月12日该媒体报道提到:......\",\n \"key_facts\": [\"关键事实1(含日期/数字)\", \"关键事实2(含日期/数字)\"]\n },\n \"post\": {\n \"title\": \"20字内标题示例\",\n \"body\": \"不少于 80 字的正文......\",\n \"tags\": [\"#热点\", \"#今日新闻\", \"#小红书运营\"],\n \"real_topics\": [\"#人工智能\", \"#AI资讯\", \"#科技观察\"],\n \"media\": [\"/abs/path/cover.png\", \"/abs/path/card_1.png\"]\n }\n}","type":"text"}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布前必须执行校验脚本:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 普通模式\nnode ./scripts/verify_publish_payload.mjs --in ./data/publish_payload.json --policy ./config/verify_publish_policy.json --tag-registry ./data/tag_registry.json --min-registry-tags 12 --require-source-evidence on --strict-anti-ai on --json\n\n# 今天热点模式(强制 source.date = 今天)\nnode ./scripts/verify_publish_payload.mjs --in ./data/publish_payload.json --policy ./config/verify_publish_policy.json --tag-registry ./data/tag_registry.json --min-registry-tags 12 --require-source-evidence on --strict-anti-ai on --mode hot --json","type":"text"}]},{"type":"ordered_list","attrs":{"order":3,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布前必须执行内容审核脚本(分层规则 + AI):","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node ./scripts/review_publish_payload.mjs --in ./data/publish_payload.json --policy ./config/review_policy.json --taxonomy ./config/review_taxonomy.json --ai-provider auto --require-ai off --mode hot --json","type":"text"}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"只有当校验和审核结果都 ","type":"text"},{"text":"ok=true","type":"text","marks":[{"type":"code_inline"}]},{"text":" 才允许进入发布页点击“发布/提交”。 校验策略在 ","type":"text"},{"text":"./config/verify_publish_policy.json","type":"text","marks":[{"type":"code_inline"}]},{"text":",审核策略在 ","type":"text"},{"text":"./config/review_policy.json","type":"text","marks":[{"type":"code_inline"}]},{"text":",分层风险路径在 ","type":"text"},{"text":"./config/review_taxonomy.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"任一门禁失败必须中止流程并提示补齐,禁止“只传截图直接发”。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"禁止链接(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题/正文/标签里禁止出现任何链接或域名形态(","type":"text"},{"text":"http/https","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"www.","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"xxx.com/.cn/...","type":"text","marks":[{"type":"code_inline"}]},{"text":")。否则有封禁风险。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果内容生成遇到困难或校验不通过:宁可中止,不要“随便发一条”。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"反 AI 识别与真实标签(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不承诺“100% 不被识别为 AI”;目标是显著降低风险。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"正文必须有“个人视角 + 具体事实信号(数字/日期/来源提及)”,并规避模板腔。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布前必须通过 ","type":"text"},{"text":"review_publish_payload","type":"text","marks":[{"type":"code_inline"}]},{"text":" 审核门禁,要求 ","type":"text"},{"text":"decision=pass","type":"text","marks":[{"type":"code_inline"}]},{"text":",并输出 ","type":"text"},{"text":"risk_path","type":"text","marks":[{"type":"code_inline"}]},{"text":"、证据和 ","type":"text"},{"text":"review_queue","type":"text","marks":[{"type":"code_inline"}]},{"text":" 供复核。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"source.evidence_snippet","type":"text","marks":[{"type":"code_inline"}]},{"text":" 与 ","type":"text"},{"text":"source.key_facts","type":"text","marks":[{"type":"code_inline"}]},{"text":" 必填,且能回溯到来源事实。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标签与 ","type":"text"},{"text":"post.real_topics","type":"text","marks":[{"type":"code_inline"}]},{"text":" 都必须来自真实话题池 ","type":"text"},{"text":"data/tag_registry.json","type":"text","marks":[{"type":"code_inline"}]},{"text":",禁止自造标签。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止自动把 ","type":"text"},{"text":"#标签","type":"text","marks":[{"type":"code_inline"}]},{"text":" 拼进正文冒充话题。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布前必须在小红书发布页手动选择至少 3 个真实话题,然后由 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 执行最终点击发布。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"示例:准备真实标签池(建议每天更新):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cat > ./data/tag_registry.json \u003c\u003c'JSON'\n{\n \"updated_at\": \"2026-02-24\",\n \"source\": {\n \"platform\": \"xiaohongshu\",\n \"method\": \"manual_from_publish_topic_picker\",\n \"url\": \"https://creator.xiaohongshu.com/creator/publish\"\n },\n \"tags\": [\"#AI热点\", \"#人工智能\", \"#行业观察\", \"#科技新闻\", \"#AI资讯\", \"#科技观察\"]\n}\nJSON","type":"text"}]},{"type":"paragraph","content":[{"text":"发布执行方式(唯一):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"本仓库只负责“数据准备 + 门禁校验 + 审核校验”;不再提供发布自动化脚本。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"浏览器动作必须由 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 串行执行:预检 -> 填充 -> 读回校验 -> 发布 -> 回查。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若任一门禁失败(","type":"text"},{"text":"verify/review","type":"text","marks":[{"type":"code_inline"}]},{"text":" 非 ","type":"text"},{"text":"ok=true","type":"text","marks":[{"type":"code_inline"}]},{"text":"),必须停止在“发布前”,禁止继续点击提交。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:发布编排器(流程编排,不是仓库脚本):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"预检:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"入口路由固定从 ","type":"text"},{"text":"https://creator.xiaohongshu.com/publish/publish","type":"text","marks":[{"type":"code_inline"}]},{"text":" 进入;禁止把 ","type":"text"},{"text":"/creator/*","type":"text","marks":[{"type":"code_inline"}]},{"text":" 作为首入口。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若被跳到 ","type":"text"},{"text":"https://creator.xiaohongshu.com/new/home","type":"text","marks":[{"type":"code_inline"}]},{"text":"(“你访问的页面不见了”),立即回到 ","type":"text"},{"text":"/publish/publish","type":"text","marks":[{"type":"code_inline"}]},{"text":" 重试。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"进入发布页后先切到“图文”模式,再上传图片;未切图文不进入后续步骤。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"填充:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"写标题、正文、标签/话题、可见性。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":3,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"读回校验:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"校验通过才允许点击发布。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"点击发布后等待页面状态稳定并记录 URL。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":5,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"回查:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"先检查 URL 参数包含 ","type":"text"},{"text":"published=true","type":"text","marks":[{"type":"code_inline"}]},{"text":";","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"再从页面菜单进入“笔记管理”做二次确认,不允许硬编码管理页直链回查。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:路由与状态稳定性(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"稳定入口只认 ","type":"text"},{"text":"/publish/publish","type":"text","marks":[{"type":"code_inline"}]},{"text":";其他页面只作为中转,不作为成功判定依据。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"“发布页可用”不等于“管理页可用”:发布后必须菜单跳转二次查验。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若发布页元素未出现,先检查是否处于“图文模式 + 图片已上传”状态,再判断失败。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:选择器双通道(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"第一通道(默认):语义定位(","type":"text"},{"text":"placeholder + role + 可见性 + 附近文案","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"第二通道(兜底):DOM 结构线索定位(例如标题输入框 placeholder 语义 + 正文编辑器 ","type":"text"},{"text":"tiptap/ProseMirror","type":"text","marks":[{"type":"code_inline"}]},{"text":" 语义类名)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"禁止只依赖 ","type":"text"},{"text":"snapshot ref","type":"text","marks":[{"type":"code_inline"}]},{"text":" 或 ","type":"text"},{"text":"@e1/@e2","type":"text","marks":[{"type":"code_inline"}]},{"text":" 序号;每个关键动作前后都要 ","type":"text"},{"text":"snapshot -i","type":"text","marks":[{"type":"code_inline"}]},{"text":" 二次确认。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DOM 兜底只作为会话级临时手段,命中后仍需“读回校验”确认字段正确,不把脆弱 selector 当硬依赖。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:写入可靠性(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题字段必须满足:单行、可见、可编辑、placeholder 命中“标题”语义。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"正文字段必须满足:多行或 ","type":"text"},{"text":"contenteditable","type":"text","marks":[{"type":"code_inline"}]},{"text":"、可见、可编辑、placeholder/附近文本命中“正文/内容”语义。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"写入后必须做“双向读回校验”:同时读取标题和正文,计算 ","type":"text"},{"text":"title_len","type":"text","marks":[{"type":"code_inline"}]},{"text":" 与 ","type":"text"},{"text":"body_len","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"错位判定:若 ","type":"text"},{"text":"title_len > 20","type":"text","marks":[{"type":"code_inline"}]},{"text":" 且 ","type":"text"},{"text":"body_len \u003c 80","type":"text","marks":[{"type":"code_inline"}]},{"text":",或标题命中长段正文特征(大量换行/句号),判定为写入错位。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"错位自愈:自动执行“交换重写”一次(清空标题与正文 -> 标题写短标题 -> 正文写正文 -> 读回再校验);仍失败则中止并回报失败,不允许继续提交。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"强制规则:标题禁止包含 ","type":"text"},{"text":"#","type":"text","marks":[{"type":"code_inline"}]},{"text":" 标签、长段正文、链接;标签必须通过小红书发布页“标签/话题交互”选择,不把标签文本塞进标题。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:草稿确认闭环(强制):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"点击“暂存离开”后,必须等待并验证“保存成功/已保存草稿”类 toast。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"进入草稿列表,验证出现“新草稿条目”。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"新条目校验最少包含:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题前缀匹配本次标题;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"时间戳在本次运行窗口内(建议 2 分钟内);","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"打开草稿后读回 ","type":"text"},{"text":"title/body/media/tags","type":"text","marks":[{"type":"code_inline"}]},{"text":" 仍满足门禁。","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"任一校验失败判定为“草稿保存失败”,允许重试 1 次;重试后仍失败则中止流程。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:图片预处理(无脚本版):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不新增仓库脚本;统一采用“发布前本地预处理 + 读回尺寸确认”。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"推荐目标尺寸:","type":"text"},{"text":"1242x1660","type":"text","marks":[{"type":"code_inline"}]},{"text":"(3:4 竖版)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"可选命令(单次执行,不落仓库脚本):","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# macOS: 先居中裁剪再缩放到 1242x1660(按需替换输入输出路径)\nsips -c 1660 1242 ./data/assets/in.png --out ./data/assets/out_1242x1660.png","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"上传后必须在发布页确认缩略图比例正常;若拉伸/裁切异常,先替换素材再继续。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:发布前硬校验(强制):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题长度 ","type":"text"},{"text":"\u003c= 20","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"正文长度 ","type":"text"},{"text":">= 80","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"已上传图片(图文至少 1 张,且可见缩略图)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"已选择真实话题 ","type":"text"},{"text":">= 3","type":"text","marks":[{"type":"code_inline"}]},{"text":"(通过小红书话题交互选择,不是正文拼接)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"标题/正文/标签无链接词(","type":"text"},{"text":"http","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"https","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"www.","type":"text","marks":[{"type":"code_inline"}]},{"text":"、域名形态)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"任一不满足直接中止,不允许“先发再修”。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P0:发布后双重确认(强制):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"第一重:发布后 URL 含 ","type":"text"},{"text":"published=true","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"第二重:从发布页菜单进入“笔记管理”,确认列表出现新笔记(标题前缀 + 时间窗口)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"管理页若被重定向或不可达,判定“回查未完成”,记录 ","type":"text"},{"text":"run_log","type":"text","marks":[{"type":"code_inline"}]},{"text":" 并提示人工复核。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P1:热点到 payload 半自动(无脚本版):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不新增 ","type":"text"},{"text":"newsnow -> payload","type":"text","marks":[{"type":"code_inline"}]},{"text":" 代码生成器;改为会话模板填充。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"采集热点后,按以下模板生成 ","type":"text"},{"text":"data/publish_payload.json","type":"text","marks":[{"type":"code_inline"}]},{"text":",人工只改“观点段”:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"topic\": \"今日热点:\u003c主题>\",\n \"source\": {\n \"name\": \"\u003c来源名>\",\n \"url\": \"\u003c来源URL>\",\n \"date\": \"YYYY-MM-DD\",\n \"evidence_snippet\": \"\u003c原文证据摘录>\",\n \"key_facts\": [\"\u003c事实1:含日期/数字>\", \"\u003c事实2:含日期/数字>\"]\n },\n \"post\": {\n \"title\": \"\u003c8-20字标题,不含标签>\",\n \"body\": \"\u003c观点段+事实段,不少于80字>\",\n \"tags\": [\"#标签1\", \"#标签2\", \"#标签3\"],\n \"real_topics\": [\"#真实话题1\", \"#真实话题2\", \"#真实话题3\"],\n \"media\": [\"/abs/path/1.png\"]\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"P1:标签/话题池维护(无脚本版):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"每天第一次发布前,手动刷新一次 ","type":"text"},{"text":"data/tag_registry.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"(从小红书发布页话题选择器抄录)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"若当天未刷新,流程必须回报风险提示并建议先刷新后再发布。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"门禁保持不变:","type":"text"},{"text":"tags","type":"text","marks":[{"type":"code_inline"}]},{"text":" 与 ","type":"text"},{"text":"real_topics","type":"text","marks":[{"type":"code_inline"}]},{"text":" 都必须命中 ","type":"text"},{"text":"tag_registry","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P1:流程可观测(无脚本版):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"每次运行结束都产出 ","type":"text"},{"text":"data/run_log/\u003cYYYY-MM-DD_HH-mm-ss>.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"(手工写文件即可,不新增脚本)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"建议字段:","type":"text"},{"text":"steps","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"durations_ms","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"failed_step","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"error_message","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"screenshots","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"result_url","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"draft_check","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"editor_check","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"route_check","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"post_publish_check","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P1:固定模板(强烈建议):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"固定标题模板:","type":"text"},{"text":"[主题词]+[观点/结论]","type":"text","marks":[{"type":"code_inline"}]},{"text":",目标 12~18 字,留 2~8 字缓冲避免超长。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"固定正文模板:","type":"text"},{"text":"开场观点 -> 事实1 -> 事实2 -> 个人判断 -> 行动建议","type":"text","marks":[{"type":"code_inline"}]},{"text":",默认 >120 字。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"固定标签与话题池:仅从 ","type":"text"},{"text":"data/tag_registry.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" 选取,避免临场造词导致门禁失败。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"P2:回归用例(每日 smoke,手工执行):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"场景 1:仅存草稿(不发布)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"场景 2:草稿后二次编辑再存草稿。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"场景 3:正式发布(通过全部门禁)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"每个场景都输出一份 ","type":"text"},{"text":"run_log","type":"text","marks":[{"type":"code_inline"}]},{"text":",用于对比“定位稳定性/错位率”。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"流程(浏览器侧全部由 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 完成):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"确保已登录(先完成上面的 A,或已有有效登录态)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"准备并校验 ","type":"text"},{"text":"data/publish_payload.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"(必须 ","type":"text"},{"text":"ok=true","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"打开 ","type":"text"},{"text":"https://creator.xiaohongshu.com/publish/publish","type":"text","marks":[{"type":"code_inline"}]},{"text":",先 ","type":"text"},{"text":"snapshot -i","type":"text","marks":[{"type":"code_inline"}]},{"text":" 获取最新结构。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"切图文模式并上传媒体(确认缩略图比例与数量)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"用“语义定位优先 + DOM 兜底”填写标题与正文,写入后执行“双向读回校验 + 错位自愈”。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"通过小红书标签交互选择标签与真实话题(至少 3 个),不要把标签写进标题。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"执行发布前硬校验(标题、正文、图片、话题、无链接词)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"点击“暂存离开”并执行草稿闭环校验(toast + 列表新条目 + 读回)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"点击“发布/提交”前暂停,要求用户确认最终预览。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布后执行双重确认(","type":"text"},{"text":"published=true","type":"text","marks":[{"type":"code_inline"}]},{"text":" + 菜单进入笔记管理二次查验),并写入 ","type":"text"},{"text":"run_log","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"发布结果输出契约(JSON):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"task\": \"xhs_publish\",\n \"ok\": true,\n \"result_url\": \"https://creator.xiaohongshu.com/....\",\n \"content_checks\": {\n \"title_len\": 18,\n \"body_len\": 136,\n \"tag_count\": 3,\n \"real_topic_count\": 3,\n \"editor_alignment_ok\": true,\n \"draft_saved_ok\": true,\n \"publish_precheck_ok\": true,\n \"published_param_ok\": true,\n \"manage_menu_check_ok\": true,\n \"topic\": \"今日热点:xxxx\",\n \"source_date\": \"2026-02-12\"\n },\n \"artifacts\": {\n \"payload_json\": \"data/publish_payload.json\",\n \"media_inputs\": [\"...\"],\n \"run_log_json\": \"data/run_log/2026-02-27_14-36-00.json\",\n \"error_screenshot\": null\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"发布失败时 ","type":"text"},{"text":"ok=false","type":"text","marks":[{"type":"code_inline"}]},{"text":",并返回 ","type":"text"},{"text":"error_message","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"error_screenshot","type":"text","marks":[{"type":"code_inline"}]},{"text":" 路径、未通过的 ","type":"text"},{"text":"missing_checks","type":"text","marks":[{"type":"code_inline"}]},{"text":" 与 ","type":"text"},{"text":"failed_stage","type":"text","marks":[{"type":"code_inline"}]},{"text":"(","type":"text"},{"text":"preflight/fill/readback/publish/postcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":")。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"C. 导出创作者中心数据(CSV/XLSX 或截图)","type":"text"}]},{"type":"paragraph","content":[{"text":"目标:把创作者中心关键数据导出到 ","type":"text"},{"text":"data/exports/\u003cYYYY-MM-DD>/","type":"text","marks":[{"type":"code_inline"}]},{"text":",用于后续分析。","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"确认已登录。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"用 ","type":"text"},{"text":"agent-browser-stealth","type":"text","marks":[{"type":"code_inline"}]},{"text":" 进入创作者中心的常用分析页(仪表盘/内容分析/粉丝分析)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"每个页面:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"优先使用页面自带导出(如有)到 ","type":"text"},{"text":"data/exports/\u003cdate>/","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"无导出时:保存关键区块截图到同目录","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"记录:导出时间范围、口径说明、页面 URL。","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"本地 CLI(本技能自带)","type":"text"}]},{"type":"paragraph","content":[{"text":"命令:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./bin/xhs-skill.mjs qr show --in \u003cpngPath>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./bin/xhs-skill.mjs cookies normalize --in \u003cjsonPath> --out \u003coutPath>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./bin/xhs-skill.mjs cookies status --in \u003ccookiesJsonPath>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./bin/xhs-skill.mjs cookies to-header --in \u003ccookiesJsonPath>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./scripts/verify_publish_payload.mjs --in \u003cpayloadJsonPath> --policy ./config/verify_publish_policy.json --tag-registry ./data/tag_registry.json --min-registry-tags 12 --require-source-evidence on --strict-anti-ai on [--mode hot]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"node ./scripts/review_publish_payload.mjs --in \u003cpayloadJsonPath> --policy ./config/review_policy.json --taxonomy ./config/review_taxonomy.json --ai-provider auto --require-ai off [--mode hot]","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"D. 轻量发版流程(维护者)","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"先跑本地门禁:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"npm run check:constraints","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"npm test","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"查看改动只包含预期文件:","type":"text"},{"text":"git status --short","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"用中文 Conventional Commit 提交(示例):","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"docs(skill): 补充发版前快速自检清单","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"ordered_list","attrs":{"order":4,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"发布到 ClawHub(patch):","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"clawhub sync --all --bump patch --changelog \"docs: 补充发版前快速自检清单\"","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"xhs-skill","author":"@skillopedia","source":{"stars":2012,"repo_name":"openclaw-master-skills","origin_url":"https://github.com/leoyeai/openclaw-master-skills/blob/HEAD/skills/xhs-skill/SKILL.md","repo_owner":"leoyeai","body_sha256":"d30a362d952b9c6d232e7400f191f3fa769f4e0a73ddb694922ee028dd594382","cluster_key":"364b0a2e6843370ea149c15c79bf73cdc595ae60db7b71b4e78b9f0260fe1830","clean_bundle":{"format":"clean-skill-bundle-v1","source":"leoyeai/openclaw-master-skills/skills/xhs-skill/SKILL.md","attachments":[{"id":"ed6f2b37-25c4-5c67-83a2-f8fa5c38796d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ed6f2b37-25c4-5c67-83a2-f8fa5c38796d/attachment.json","path":"_meta.json","size":1335,"sha256":"1ed8495eeeaa84e91fdb47927c8a8637b93a8cb3c120e9afb56ee52ddecc7d2e","contentType":"application/json; charset=utf-8"},{"id":"82433097-dee2-5e1f-83c9-ef37c1297b1d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/82433097-dee2-5e1f-83c9-ef37c1297b1d/attachment.yaml","path":"agents/openai.yaml","size":266,"sha256":"54d9cae189faa410af8617b3da178716488b64132054f6e3e82e7139c10a0a5c","contentType":"application/yaml; charset=utf-8"},{"id":"b6312dc7-a486-5d48-8c02-e812fd9502b7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b6312dc7-a486-5d48-8c02-e812fd9502b7/attachment.mjs","path":"bin/xhs-skill.mjs","size":241,"sha256":"d52b0df67aeff04ede0c4b80f7eaa3dd857ad6b94c1062f60addb8deced35542","contentType":"text/javascript"},{"id":"43bdee41-9363-5d48-b958-4fd5b0bb7bcf","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/43bdee41-9363-5d48-b958-4fd5b0bb7bcf/attachment.mjs","path":"cli.mjs","size":5629,"sha256":"ab8dd2ab2392dbafd63482680c46b9d1656a5a46667a15a73cb5c350690c432d","contentType":"text/javascript"},{"id":"a9f70bd1-6638-5cf4-8ad5-6e325acdaf0c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a9f70bd1-6638-5cf4-8ad5-6e325acdaf0c/attachment.json","path":"config/review_policy.json","size":1625,"sha256":"8a756b8773d8a9c00a3bf7a60ba43f59b3244db82b580ae06fce320bf06c7776","contentType":"application/json; charset=utf-8"},{"id":"43c4df90-4291-5900-ac59-3760fd60e833","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/43c4df90-4291-5900-ac59-3760fd60e833/attachment.json","path":"config/review_taxonomy.json","size":1695,"sha256":"5b8f5411056c7e05f43c1148d1a8a33dcf4aa05a40b00ca051932721222465bf","contentType":"application/json; charset=utf-8"},{"id":"ee81b38f-5ae1-5d43-96a5-7085d3487cd6","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ee81b38f-5ae1-5d43-96a5-7085d3487cd6/attachment.json","path":"config/verify_publish_policy.json","size":2026,"sha256":"0f0cff1006186be5e9e2e8389b95cb74fcfa94c42c705558aa0c3a5530b3646d","contentType":"application/json; charset=utf-8"},{"id":"9f190483-d473-5afc-a1e0-b60fdc56841d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9f190483-d473-5afc-a1e0-b60fdc56841d/attachment.mjs","path":"lib/cookies.mjs","size":4294,"sha256":"e60ff8fefc489850cf0f4b195f2aa3f95cfaabe84d92950d5bb467d36ef2fb91","contentType":"text/javascript"},{"id":"be130fc0-6761-52f3-9088-70ac7a274e46","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/be130fc0-6761-52f3-9088-70ac7a274e46/attachment.mjs","path":"lib/image.mjs","size":2179,"sha256":"10db134e2fc9bd9aae5bf94da374444a2f1a4f22abde0e193a359ee405af8359","contentType":"text/javascript"},{"id":"966d5689-c6b3-502e-992e-12be65b20cc1","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/966d5689-c6b3-502e-992e-12be65b20cc1/attachment.mjs","path":"lib/qr.mjs","size":572,"sha256":"4c8532e1dfcb9bd95501f8d8d44abb0ddcb8c80e7c4f3dc13985f71e1c2876fa","contentType":"text/javascript"},{"id":"365f195d-ea72-56d1-8a36-03dd86b5d735","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/365f195d-ea72-56d1-8a36-03dd86b5d735/attachment.json","path":"package.json","size":364,"sha256":"1c8aa3471ecb77ab837d62ac9d9ce594a293150257272db9f38af18d24a5bd98","contentType":"application/json; charset=utf-8"},{"id":"0dbb9c06-9dc8-5b57-b845-8540441aeda3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0dbb9c06-9dc8-5b57-b845-8540441aeda3/attachment.mjs","path":"scripts/review_publish_payload.mjs","size":34121,"sha256":"32739354c7a5d06cb148ff1faa11d9f05b0ee1850d1666fe3d074f1687e0d28e","contentType":"text/javascript"},{"id":"f0aba041-4f47-5186-8b09-6db80ab15828","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f0aba041-4f47-5186-8b09-6db80ab15828/attachment.mjs","path":"scripts/verify_login.mjs","size":4013,"sha256":"f12dccaaeb0c6f140031ee052a4f2e8612191bced6aa9054dd564b042365387d","contentType":"text/javascript"},{"id":"f79f982b-684e-5ac5-815f-6227f2d58326","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f79f982b-684e-5ac5-815f-6227f2d58326/attachment.mjs","path":"scripts/verify_publish_payload.mjs","size":27703,"sha256":"3cbb121790f6ecc39248036c74bfde5d97946986cb55a87191536b8f27d3db8a","contentType":"text/javascript"}],"bundle_sha256":"495e445864ec440d2a9ba1c12e6b5e2ffacf3801d700a26c4d1ec8309401f46c","attachment_count":14,"text_attachments":14,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/xhs-skill/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"browser-automation-scraping","category_label":"Browser"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"browser-automation-scraping","metadata":{"openclaw":{"emoji":"📌","stage":"workflow"}},"import_tag":"clean-skills-v1","description":"小红书(创作者中心)登录拿 cookies、发布笔记、导出数据的单一入口技能(浏览器交互委托 agent-browser-stealth)"}},"renderedAt":1782987491974}

本技能是 的合并版,目标是让用户只需要 一次即可开始使用。 约束: - 所有浏览器交互(打开页面/点击/输入/上传/截图/登录/导出)全部委托 。 - 禁止在本仓库编写/维护发布编排脚本(如 );发布动作必须在会话中由 执行。 - 禁止使用 (旧通道禁用,统一使用 )。 - 所有敏感数据(cookies、导出文件、截图)只落地在本机 目录,不要粘贴到聊天里。 执行硬约束(稳定性): - 同一 session 禁止并发操作(串行执行),否则容易触发 假失败。 - 的 ref 会漂移:关键动作前后必须重抓 ,并用 做二次定位兜底。 - 扫码不等于登录成功;必须做后验校验(见下方 A 节“登录成功判定”)。 安装 说明: 仅用于本技能自带的本地 CLI(二维码解码、cookies 工具)。如果你不需要解码二维码/转换 cookies,也可以只用 完成扫码与导出。 目录约定(本机) 建议在你运行命令的工作目录下准备: - :登录页二维码截图(PNG) - :导出的原始 cookies(JSON) - :归一化后的 cookies(JSON) - :导出数据(CSV/XLSX/截图) - :发布笔记用的图标/配图素材与来源记录 A. 登录(扫码)并保存 cookies 目标:登录小红书创作者中心并导出 cookies,避免频繁重复登录。 1. 用 打开登录页: - - 若默认展示「手机号/…