@gobing-ai/knowledge-kit 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +2372 -1722
  3. package/package.json +1 -1
  4. package/plugins/generations/image-gen/README.md +108 -0
  5. package/plugins/generations/image-gen/assets/sample/cover__clean-webapp-ui.jpg +0 -0
  6. package/plugins/generations/image-gen/assets/sample/cover__cute.jpg +0 -0
  7. package/plugins/generations/image-gen/assets/sample/cover__daily-news.jpg +0 -0
  8. package/plugins/generations/image-gen/assets/sample/cover__editorial.jpg +0 -0
  9. package/plugins/generations/image-gen/assets/sample/cover__fresh.jpg +0 -0
  10. package/plugins/generations/image-gen/assets/sample/cover__minimalist.jpg +0 -0
  11. package/plugins/generations/image-gen/assets/sample/cover__photorealistic.jpg +0 -0
  12. package/plugins/generations/image-gen/assets/sample/cover__sketch.jpg +0 -0
  13. package/plugins/generations/image-gen/assets/sample/cover__technical-diagram.jpg +0 -0
  14. package/plugins/generations/image-gen/assets/sample/cover__vibrant.jpg +0 -0
  15. package/plugins/generations/image-gen/assets/sample/cover__warm.jpg +0 -0
  16. package/plugins/generations/image-gen/assets/sample/cover__xhs-knowledge.jpg +0 -0
  17. package/plugins/generations/image-gen/assets/sample/daily-news-cover__clean-webapp-ui.jpg +0 -0
  18. package/plugins/generations/image-gen/assets/sample/daily-news-cover__cute.jpg +0 -0
  19. package/plugins/generations/image-gen/assets/sample/daily-news-cover__daily-news.jpg +0 -0
  20. package/plugins/generations/image-gen/assets/sample/daily-news-cover__editorial.jpg +0 -0
  21. package/plugins/generations/image-gen/assets/sample/daily-news-cover__fresh.jpg +0 -0
  22. package/plugins/generations/image-gen/assets/sample/daily-news-cover__minimalist.jpg +0 -0
  23. package/plugins/generations/image-gen/assets/sample/daily-news-cover__photorealistic.jpg +0 -0
  24. package/plugins/generations/image-gen/assets/sample/daily-news-cover__sketch.jpg +0 -0
  25. package/plugins/generations/image-gen/assets/sample/daily-news-cover__technical-diagram.jpg +0 -0
  26. package/plugins/generations/image-gen/assets/sample/daily-news-cover__vibrant.jpg +0 -0
  27. package/plugins/generations/image-gen/assets/sample/daily-news-cover__warm.jpg +0 -0
  28. package/plugins/generations/image-gen/assets/sample/daily-news-cover__xhs-knowledge.jpg +0 -0
  29. package/plugins/generations/image-gen/assets/sample/free__clean-webapp-ui.jpg +0 -0
  30. package/plugins/generations/image-gen/assets/sample/free__cute.jpg +0 -0
  31. package/plugins/generations/image-gen/assets/sample/free__daily-news.jpg +0 -0
  32. package/plugins/generations/image-gen/assets/sample/free__editorial.jpg +0 -0
  33. package/plugins/generations/image-gen/assets/sample/free__fresh.jpg +0 -0
  34. package/plugins/generations/image-gen/assets/sample/free__minimalist.jpg +0 -0
  35. package/plugins/generations/image-gen/assets/sample/free__photorealistic.jpg +0 -0
  36. package/plugins/generations/image-gen/assets/sample/free__sketch.jpg +0 -0
  37. package/plugins/generations/image-gen/assets/sample/free__technical-diagram.jpg +0 -0
  38. package/plugins/generations/image-gen/assets/sample/free__vibrant.jpg +0 -0
  39. package/plugins/generations/image-gen/assets/sample/free__warm.jpg +0 -0
  40. package/plugins/generations/image-gen/assets/sample/free__xhs-knowledge.jpg +0 -0
  41. package/plugins/generations/image-gen/assets/sample/illustration__clean-webapp-ui.jpg +0 -0
  42. package/plugins/generations/image-gen/assets/sample/illustration__cute.jpg +0 -0
  43. package/plugins/generations/image-gen/assets/sample/illustration__daily-news.jpg +0 -0
  44. package/plugins/generations/image-gen/assets/sample/illustration__editorial.jpg +0 -0
  45. package/plugins/generations/image-gen/assets/sample/illustration__fresh.jpg +0 -0
  46. package/plugins/generations/image-gen/assets/sample/illustration__minimalist.jpg +0 -0
  47. package/plugins/generations/image-gen/assets/sample/illustration__photorealistic.jpg +0 -0
  48. package/plugins/generations/image-gen/assets/sample/illustration__sketch.jpg +0 -0
  49. package/plugins/generations/image-gen/assets/sample/illustration__technical-diagram.jpg +0 -0
  50. package/plugins/generations/image-gen/assets/sample/illustration__vibrant.jpg +0 -0
  51. package/plugins/generations/image-gen/assets/sample/illustration__warm.jpg +0 -0
  52. package/plugins/generations/image-gen/assets/sample/illustration__xhs-knowledge.jpg +0 -0
  53. package/plugins/generations/image-gen/assets/sample/xhs-card__clean-webapp-ui.jpg +0 -0
  54. package/plugins/generations/image-gen/assets/sample/xhs-card__cute.jpg +0 -0
  55. package/plugins/generations/image-gen/assets/sample/xhs-card__daily-news.jpg +0 -0
  56. package/plugins/generations/image-gen/assets/sample/xhs-card__editorial.jpg +0 -0
  57. package/plugins/generations/image-gen/assets/sample/xhs-card__fresh.jpg +0 -0
  58. package/plugins/generations/image-gen/assets/sample/xhs-card__minimalist.jpg +0 -0
  59. package/plugins/generations/image-gen/assets/sample/xhs-card__photorealistic.jpg +0 -0
  60. package/plugins/generations/image-gen/assets/sample/xhs-card__sketch.jpg +0 -0
  61. package/plugins/generations/image-gen/assets/sample/xhs-card__technical-diagram.jpg +0 -0
  62. package/plugins/generations/image-gen/assets/sample/xhs-card__vibrant.jpg +0 -0
  63. package/plugins/generations/image-gen/assets/sample/xhs-card__warm.jpg +0 -0
  64. package/plugins/generations/image-gen/assets/sample/xhs-card__xhs-knowledge.jpg +0 -0
  65. package/plugins/generations/image-gen/dist/index.js +102 -58
  66. package/plugins/generations/image-gen/scripts/compose-e2e-artifact.ts +5 -21
  67. package/plugins/generations/image-gen/scripts/gen-samples.ts +208 -0
  68. package/plugins/generations/image-gen/src/compose/chromium.ts +2 -3
  69. package/plugins/generations/image-gen/src/presets.ts +6 -3
  70. package/plugins/generations/image-gen/src/providers/errors.ts +16 -1
  71. package/plugins/generations/image-gen/src/providers/minimax.ts +46 -17
  72. package/plugins/ingestions/web-search/src/index.ts +1 -1
  73. package/plugins/kk/README.md +18 -0
  74. package/plugins/kk/commands/image-extract.md +1 -0
  75. package/plugins/kk/commands/image-generate.md +1 -0
  76. package/plugins/kk/commands/tell-me.md +1 -0
  77. package/plugins/kk/commands/workflow-run.md +7 -1
  78. package/plugins/kk/decisions/extract/it-topics.yaml +24 -0
  79. package/plugins/kk/decisions/kk-itc.yaml +6 -4
  80. package/plugins/kk/plugin.json +1 -1
  81. package/plugins/kk/publish-presets/daily-ai-voice-migration.json +146 -0
  82. package/plugins/kk/publish-presets/daily-ai-voice.json +15 -7
  83. package/plugins/kk/schedules/kk-collect.grok-bot.md.tmpl +69 -0
  84. package/plugins/kk/schedules/kk-daily-ai-voice3.cron.tmpl +18 -0
  85. package/plugins/kk/schedules/kk-daily-publish3-cn-peak.cron.tmpl +15 -5
  86. package/plugins/kk/schedules/kk-daily-publish3-overseas.cron.tmpl +9 -4
  87. package/plugins/kk/scripts/daily-scheduled-run.ts +91 -41
  88. package/plugins/kk/scripts/daily-stages.ts +394 -53
  89. package/plugins/kk/scripts/kk-workflow-stages.ts +190 -0
  90. package/plugins/kk/scripts/safety-artifact-check.ts +70 -28
  91. package/plugins/kk/scripts/voice3-publish-window.ts +202 -0
  92. package/plugins/kk/skills/article-adapt/SKILL.md +1 -0
  93. package/plugins/kk/skills/audio-authoring/SKILL.md +1 -0
  94. package/plugins/kk/skills/content-judge/SKILL.md +1 -0
  95. package/plugins/kk/skills/content-safety/SKILL.md +1 -0
  96. package/plugins/kk/skills/content-safety/references/platforms/podcast-salty.md +41 -0
  97. package/plugins/kk/skills/content-safety/references/platforms/surfdash.md +36 -0
  98. package/plugins/kk/skills/content-safety/references/platforms/xhs.md +39 -0
  99. package/plugins/kk/skills/explain-things/SKILL.md +1 -0
  100. package/plugins/kk/skills/image-authoring/SKILL.md +1 -0
  101. package/plugins/kk/skills/itc-generating/SKILL.md +1 -0
  102. package/plugins/kk/skills/publish/SKILL.md +1 -0
  103. package/plugins/kk/skills/smart-seo/SKILL.md +1 -0
  104. package/plugins/kk/skills/storm-research/SKILL.md +1 -0
  105. package/plugins/kk/skills/taste-unslop/SKILL.md +1 -0
  106. package/plugins/kk/skills/topic/SKILL.md +1 -0
  107. package/plugins/kk/skills/web-automation/SKILL.md +1 -0
  108. package/plugins/kk/skills/xhs-images/SKILL.md +1 -0
  109. package/plugins/kk/workflows/kk-collect.yaml +3 -3
  110. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +21 -19
  111. package/plugins/kk/workflows/kk-daily-ai-voice3.yaml +163 -63
  112. package/plugins/kk/workflows/kk-daily-publish3.yaml +82 -26
  113. package/plugins/kk/workflows/kk-daily-safety.yaml +39 -31
  114. package/plugins/kk/workflows/kk-itc-author.yaml +75 -0
  115. package/plugins/kk/workflows/kk-itc-publish-tail.yaml +25 -3
  116. package/plugins/kk/workflows/kk-itc.yaml +36 -4
  117. package/plugins/publishings/linkedin-pub/dist/index.js +21333 -0
  118. package/plugins/publishings/linkedin-pub/dist/profile-check.js +21005 -0
  119. package/plugins/publishings/linkedin-pub/package.json +19 -0
  120. package/plugins/publishings/linkedin-pub/plugin.json +12 -0
  121. package/plugins/publishings/linkedin-pub/src/index.ts +705 -0
  122. package/plugins/publishings/linkedin-pub/src/profile-check.ts +17 -0
  123. package/plugins/publishings/linkedin-pub/tsconfig.json +4 -0
  124. package/plugins/publishings/surfdash-pub/dist/index.js +53 -24
  125. package/plugins/publishings/surfdash-pub/src/index.ts +72 -25
  126. package/plugins/publishings/threads-pub/dist/index.js +7 -0
  127. package/plugins/publishings/threads-pub/src/index.ts +12 -0
  128. package/plugins/publishings/wechatmp-pub/dist/index.js +176 -32
  129. package/plugins/publishings/wechatmp-pub/src/flow.ts +298 -52
  130. package/plugins/publishings/weibo-pub/dist/index.js +100 -7
  131. package/plugins/publishings/weibo-pub/src/index.ts +111 -11
  132. package/plugins/publishings/x-pub/dist/index.js +7 -0
  133. package/plugins/publishings/x-pub/src/index.ts +11 -0
  134. package/plugins/publishings/xhs-pub/dist/index.js +164 -12
  135. package/plugins/publishings/xhs-pub/dist/profile-check.js +11 -1
  136. package/plugins/publishings/xhs-pub/src/flow.ts +194 -23
  137. package/plugins/publishings/xhs-pub/src/page.ts +26 -0
@@ -22533,6 +22533,11 @@ var TITLE_BLOCK = [
22533
22533
  'div.ProseMirror[data-placeholder*="\u6807\u9898"]'
22534
22534
  ];
22535
22535
  var TITLE_MIRROR = ["textarea#title", "textarea.js_title"];
22536
+ var PODCAST_TITLE = ["textarea.js_title"];
22537
+ var PODCAST_BODY = [
22538
+ "div.ProseMirror.ProseMirror-focused:not([data-placeholder])",
22539
+ "div.ProseMirror:not([data-placeholder])"
22540
+ ];
22536
22541
  var BODY_BLOCK = [
22537
22542
  "div.ProseMirror.ProseMirror-focused:not([data-placeholder])",
22538
22543
  "div.ProseMirror:not([data-placeholder])",
@@ -22626,17 +22631,19 @@ var VIDEO_FILE_INPUT = [
22626
22631
  ];
22627
22632
  var VIDEO_CONFIRM = ['div.weui-desktop-dialog button:has-text("\u786E\u5B9A")', 'button:has-text("\u786E\u5B9A")'];
22628
22633
  var PODCAST_UPLOAD = ["text=\u4E0A\u4F20\u97F3\u9891", 'button:has-text("\u4E0A\u4F20\u97F3\u9891")'];
22634
+ var PODCAST_ROW = (title) => `li.audio_item_wrp:has-text("${JSON.stringify(title).slice(1, -1)}"), div.audio_item_wrp:has-text("${JSON.stringify(title).slice(1, -1)}")`;
22629
22635
  var PODCAST_AUDIO_INPUT = [
22636
+ "div.weui-desktop-dialog input.weui-desktop-upload-input",
22637
+ 'div.weui-desktop-dialog input[name="audio_id"]',
22630
22638
  'div.weui-desktop-dialog input[type="file"][accept*="audio"]',
22631
- 'div.weui-desktop-dialog input[type="file"][accept*=".mp3"]',
22632
- 'input[type="file"][accept*="audio"]',
22633
- 'input[type="file"][accept*=".mp3"]'
22639
+ 'div.weui-desktop-dialog input[type="file"][accept*=".mp3"]'
22634
22640
  ];
22635
22641
  var PODCAST_COVER_INPUT = [
22636
- 'div.weui-desktop-dialog input[type="file"][accept*="image/"]',
22637
- 'div.weui-desktop-dialog input[type="file"][accept*=".png"]',
22638
- 'div.weui-desktop-dialog input[type="file"][accept*=".jpg"]'
22642
+ 'input[type="file"][accept*="image/bmp"]',
22643
+ 'div.weui-desktop-dialog input[type="file"][accept*="image/"]'
22639
22644
  ];
22645
+ var PODCAST_TITLE_INPUT = ".weui-desktop-dialog .title_form_wrp input.weui-desktop-form__input";
22646
+ var PODCAST_COVER_CHOOSER = '.weui-desktop-dialog:visible:has(h3:has-text("\u9009\u62E9\u56FE\u7247"))';
22640
22647
  var PODCAST_INSERT = ['div.weui-desktop-dialog button:has-text("\u63D2\u5165")', 'button:has-text("\u63D2\u5165")'];
22641
22648
  var AUDIO_MENU = "li.js_insertaudio";
22642
22649
  var AUDIO_TOOLBAR_TRIGGER = "#audio_music_plugin_btn";
@@ -22854,10 +22861,7 @@ async function typeTitle(page, deps) {
22854
22861
  return mirror.observed ? "mirror-agreed" : "mirror-unread";
22855
22862
  }
22856
22863
  async function readTitleMirror(page) {
22857
- const found = await trySelectors(page, TITLE_MIRROR, { visible: false }).catch(() => ({
22858
- found: false,
22859
- selector: null
22860
- }));
22864
+ const found = await trySelectors(page, TITLE_MIRROR, { visible: false });
22861
22865
  if (!found.found || !found.selector)
22862
22866
  return { observed: false, value: "" };
22863
22867
  const locator = page.locator(found.selector).first();
@@ -22869,13 +22873,24 @@ async function readTitleMirror(page) {
22869
22873
  return { observed: false, value: "" };
22870
22874
  }
22871
22875
  }
22872
- async function insertBody(page, deps) {
22876
+ async function insertBody(page, deps, selectors = BODY_BLOCK) {
22873
22877
  const body = bodyOf(deps.content);
22874
22878
  if (body.trim().length === 0)
22875
22879
  return;
22876
- const selector = await findSelector(page, BODY_BLOCK, "article body", deps.stepTimeoutMs);
22880
+ const selector = await findSelector(page, selectors, "article body", deps.stepTimeoutMs);
22877
22881
  await pasteHtml(asPlaywrightPage(page), selector, markdownToWechatHtml(body), { timeoutMs: deps.stepTimeoutMs });
22878
22882
  }
22883
+ async function typePodcastTitle(page, deps) {
22884
+ const title = titleOf(deps.content);
22885
+ if (title.length === 0)
22886
+ return;
22887
+ const sel = await findSelector(page, PODCAST_TITLE, "podcast title", deps.stepTimeoutMs);
22888
+ await fillSelector(page, sel, title);
22889
+ const locator = page.locator(sel).first();
22890
+ const mirror = typeof locator.inputValue === "function" ? await locator.inputValue() : "";
22891
+ if (mirror !== title)
22892
+ throw new Error(`podcast title: textarea.js_title reads '${mirror}' but the flow typed '${title}'`);
22893
+ }
22879
22894
  function nativeLayoutTargetScript() {
22880
22895
  return `/* ${LAYOUT_TARGET_MARKER} */ (() => {
22881
22896
  const popups = [...document.querySelectorAll('.edui-popup')].filter((popup) => {
@@ -23286,24 +23301,154 @@ async function composeVideo(input, deps, entry) {
23286
23301
  const confirm = await findSelector(page, VIDEO_CONFIRM, "video media confirm", deps.stepTimeoutMs);
23287
23302
  await clickSelector(page, confirm, deps.stepTimeoutMs);
23288
23303
  await awaitSaveBar(page, deps);
23289
- const titlePath = await typeTitle(page, deps);
23290
- await insertBody(page, deps);
23291
- return { warnings: [], titlePath, enrichWarnings: [] };
23304
+ await typePodcastTitle(page, deps);
23305
+ await insertBody(page, deps, PODCAST_BODY);
23306
+ return { warnings: [], titlePath: "mirror-agreed", enrichWarnings: [] };
23292
23307
  }
23293
23308
  async function composePodcast(input, deps, entry) {
23294
23309
  const page = entry.editor;
23310
+ const materialTitle = titleOf(deps.content);
23311
+ const reuseProbe = `(() => {
23312
+ const rows = [...document.querySelectorAll('.weui-desktop-dialog li.audio_item_wrp, .weui-desktop-dialog div.audio_item_wrp')].filter((r) => r.offsetWidth > 0);
23313
+ if (rows.length === 0) return 'LOADING';
23314
+ const row = rows.find((r) => ((r.textContent ?? '').replace(/[s\xA0]/g, '')).includes(${JSON.stringify(materialTitle).replace(/[\s\u00a0]/g, "")}));
23315
+ return row ? (row.textContent ?? '') : 'NONE';
23316
+ })()`;
23317
+ let reuseRowText = "";
23318
+ const reuseHistory = [];
23319
+ {
23320
+ const probe = async () => String(await page.evaluate(reuseProbe) ?? "");
23321
+ for (let i = 0;i < 10; i++) {
23322
+ const text = await probe();
23323
+ reuseHistory.push(text === "LOADING" || text === "ERR" ? text : text.slice(0, 25));
23324
+ if (text === "LOADING" || text === "ERR") {
23325
+ await page.waitForTimeout?.(2500);
23326
+ continue;
23327
+ }
23328
+ if (text === "NONE")
23329
+ break;
23330
+ if (!/\u8F6C\u7801\u4E2D|\u5BA1\u6838\u4E2D|\u5904\u7406\u4E2D/.test(text)) {
23331
+ reuseRowText = text;
23332
+ break;
23333
+ }
23334
+ }
23335
+ }
23336
+ if (reuseRowText) {
23337
+ const reuseReady = await waitUntil(async () => {
23338
+ const text = String(await page.evaluate(reuseProbe) ?? "");
23339
+ return text !== "ERR" && text !== "LOADING" && text !== "NONE" && !/\u8F6C\u7801\u4E2D|\u5BA1\u6838\u4E2D|\u5904\u7406\u4E2D/.test(text);
23340
+ }, 40 * 60000);
23341
+ if (!reuseReady)
23342
+ throw new Error(`\u64AD\u5BA2: \u590D\u7528\u7D20\u6750\u5217\u8868\u5728 40min \u5185\u672A\u89C1\u300C${materialTitle}\u300D\u5B8C\u6210\u8F6C\u7801/\u5BA1\u6838`);
23343
+ await clickSelector(page, await findSelector(page, [`${PODCAST_ROW(materialTitle)} label.audio_item`, PODCAST_ROW(materialTitle)], "\u64AD\u5BA2\u7D20\u6750 row", deps.stepTimeoutMs), deps.stepTimeoutMs);
23344
+ await clickSelector(page, await findSelector(page, PODCAST_INSERT, "\u63D2\u5165 control", deps.stepTimeoutMs), deps.stepTimeoutMs);
23345
+ await awaitSaveBar(page, deps);
23346
+ await typePodcastTitle(page, deps);
23347
+ await insertBody(page, deps, PODCAST_BODY);
23348
+ return { warnings: [], titlePath: "mirror-agreed", enrichWarnings: [] };
23349
+ }
23295
23350
  const upload = await findSelector(page, PODCAST_UPLOAD, "\u4E0A\u4F20\u97F3\u9891 control", deps.stepTimeoutMs);
23296
23351
  await clickSelector(page, upload, deps.stepTimeoutMs);
23297
23352
  const audioInput = await findAttachedSelector(page, PODCAST_AUDIO_INPUT, "audio file input", deps.stepTimeoutMs);
23298
- await uploadFile(asPlaywrightPage(page), audioInput, input.audio, { timeoutMs: deps.stepTimeoutMs });
23299
- const coverInput = await findAttachedSelector(page, PODCAST_COVER_INPUT, "cover file input", deps.stepTimeoutMs);
23353
+ await uploadFile(asPlaywrightPage(page), audioInput, input.audio, { timeoutMs: 120000 });
23354
+ const uploadDialog = '.weui-desktop-dialog:visible:has(h3.weui-desktop-dialog__title:text-is("\u4E0A\u4F20\u97F3\u9891"))';
23355
+ await waitUntil(async () => await page.locator(`${uploadDialog} button:has-text("\u91CD\u65B0\u4E0A\u4F20")`).count() > 0 && /100%/.test(await page.evaluate(`(() => {
23356
+ const d = [...document.querySelectorAll(".weui-desktop-dialog")].find((el) => el.offsetWidth > 0 && el.querySelector("input[name=audio_id]"));
23357
+ return d ? (d.textContent ?? "") : "";
23358
+ })()`)), 120000);
23359
+ const coverTrigger = await findSelector(page, [`${uploadDialog} .select_audio_cover .upload_cover_text`, ".select_audio_cover .upload_cover_text"], "\u4E0A\u4F20\u5C01\u9762 control (audio upload form)", deps.stepTimeoutMs);
23360
+ await clickSelector(page, coverTrigger, deps.stepTimeoutMs);
23361
+ const coverInput = await findAttachedSelector(page, PODCAST_COVER_INPUT, "cover file input (\u9009\u62E9\u56FE\u7247 chooser)", deps.stepTimeoutMs);
23300
23362
  await uploadFile(asPlaywrightPage(page), coverInput, input.cover, { timeoutMs: deps.stepTimeoutMs });
23301
- const insert = await findSelector(page, PODCAST_INSERT, "\u63D2\u5165 control", deps.stepTimeoutMs);
23302
- await clickSelector(page, insert, deps.stepTimeoutMs);
23363
+ const chooser = PODCAST_COVER_CHOOSER;
23364
+ const next = await findSelector(page, [`${chooser} button:has-text("\u4E0B\u4E00\u6B65"):not(.weui-desktop-btn_disabled):not([disabled])`], "\u64AD\u5BA2\u5C01\u9762 chooser \u4E0B\u4E00\u6B65", 30000);
23365
+ await clickSelector(page, next, deps.stepTimeoutMs);
23366
+ const cropSettled = await waitUntil(async () => await page.locator(`${chooser} button:has-text("\u4E0A\u4E00\u6B65")`).count() > 0, 15000);
23367
+ if (!cropSettled)
23368
+ throw new Error("\u64AD\u5BA2: \u5C01\u9762\u88C1\u526A\u9875\u672A\u51FA\u73B0\uFF08\u4E0B\u4E00\u6B65\u540E\u65E0\u4E0A\u4E00\u6B65\u6309\u94AE\uFF09");
23369
+ await page.waitForTimeout?.(4000);
23370
+ const finish = await findSelector(page, [`${chooser} button:has-text("\u5B8C\u6210"):not(.weui-desktop-btn_disabled):not([disabled])`], "\u64AD\u5BA2\u5C01\u9762 chooser \u5B8C\u6210", 30000);
23371
+ await clickSelector(page, finish, deps.stepTimeoutMs);
23372
+ let chooserClosed = await waitUntil(async () => await page.locator(chooser).count() === 0, 25000);
23373
+ if (!chooserClosed) {
23374
+ const confirm = await tryFindSelector(page, [`${chooser} button:has-text("\u786E\u5B9A")`], 5000);
23375
+ if (confirm) {
23376
+ await clickSelector(page, confirm, deps.stepTimeoutMs);
23377
+ chooserClosed = await waitUntil(async () => await page.locator(chooser).count() === 0, 1e4);
23378
+ }
23379
+ }
23380
+ if (!chooserClosed) {
23381
+ const residue = String(await page.evaluate(`(() => JSON.stringify([...document.querySelectorAll(".weui-desktop-dialog")]
23382
+ .filter((d) => d.offsetWidth > 0).map((d) => (d.querySelector("h3")?.textContent ?? "") + ":" + (d.textContent ?? "").replace(/\\s+/g, " ").slice(0, 120)) + " toast:" + (document.querySelector(".weui-desktop-toast")?.textContent ?? "")))()`).catch(() => null)).slice(0, 900);
23383
+ throw new Error(`\u64AD\u5BA2: \u5C01\u9762\u9009\u62E9\u5668\u5B8C\u6210\u540E\u672A\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58\u97F3\u9891\u7D20\u6750 \u2014 \u73B0\u573A\u6B8B\u7559 ${residue ?? "(probe \u5931\u8D25)"}`);
23384
+ }
23385
+ await fillSelector(page, await findSelector(page, [PODCAST_TITLE_INPUT], "\u7D20\u6750\u6807\u9898 input", deps.stepTimeoutMs), materialTitle);
23386
+ const agreed = String(await page.evaluate(`(() => {
23387
+ const dialog = [...document.querySelectorAll('.weui-desktop-dialog')].find((d) => d.querySelector('.title_form_wrp'));
23388
+ if (!dialog) return 'no-dialog';
23389
+ const cb = dialog.querySelector('.audio-upload-dialog_agreement input[type=checkbox]');
23390
+ if (!cb) return 'no-box';
23391
+ if (!cb.checked) cb.click();
23392
+ return cb.checked ? 'checked' : 'unchecked';
23393
+ })()`));
23394
+ if (agreed !== "checked")
23395
+ throw new Error(`\u64AD\u5BA2: \u670D\u52A1\u89C4\u5219\u52FE\u9009\u5931\u8D25 (${agreed})`);
23396
+ const save = await findSelector(page, [
23397
+ `${uploadDialog} button.weui-desktop-btn_primary:text-is("\u4FDD\u5B58"):not(.weui-desktop-btn_disabled):not([disabled])`
23398
+ ], "\u97F3\u9891\u7D20\u6750\u4FDD\u5B58 (enabled after cover + title + agreement)", 90000);
23399
+ await page.evaluate(`(() => {
23400
+ window.__kkToasts = [];
23401
+ new MutationObserver(() => {
23402
+ const t = document.querySelector(".weui-desktop-toast");
23403
+ if (t && t.textContent) window.__kkToasts.push(t.textContent.trim().slice(0, 200));
23404
+ }).observe(document.body, { subtree: true, childList: true, characterData: true });
23405
+ })()`);
23406
+ const saveDiagnostics = `(() => {
23407
+ const form = [...document.querySelectorAll(".weui-desktop-dialog")].find((d) => d.querySelector(".title_form_wrp"));
23408
+ if (!form) return { form: "gone" };
23409
+ const btn = [...form.querySelectorAll("button")].find((b) => (b.textContent ?? "").trim() === "\u4FDD\u5B58");
23410
+ return {
23411
+ btn: btn ? { html: btn.outerHTML.slice(0, 120), disabled: btn.disabled, offW: btn.offsetWidth } : null,
23412
+ fields: [...form.querySelectorAll("input, textarea")].map((f) => ({ cls: String(f.className ?? "").slice(0, 40), v: String(f.value ?? "").slice(0, 30), offW: f.offsetWidth, cb: f.type === "checkbox" ? f.checked : undefined })),
23413
+ toasts: (window.__kkToasts ?? []).slice(-3),
23414
+ };
23415
+ })()`;
23416
+ const saveBefore = String(await page.evaluate(saveDiagnostics).catch(() => null)).slice(0, 450);
23417
+ await clickSelector(page, save, deps.stepTimeoutMs);
23418
+ const formClosed = await waitUntil(async () => await page.locator(uploadDialog).count() === 0, 30000);
23419
+ if (!formClosed) {
23420
+ const dispatched = String(await page.evaluate(`(() => {
23421
+ const form = [...document.querySelectorAll(".weui-desktop-dialog")].find((d) => d.querySelector(".title_form_wrp"));
23422
+ const btn = form && [...form.querySelectorAll("button")].find((b) => (b.textContent ?? "").trim() === "\u4FDD\u5B58");
23423
+ if (!btn) return "no-btn";
23424
+ btn.click();
23425
+ return btn.disabled ? "was-disabled" : "clicked";
23426
+ })()`).catch(() => null));
23427
+ const dispatchClosed = await waitUntil(async () => await page.locator(uploadDialog).count() === 0, 1e4);
23428
+ if (!dispatchClosed) {
23429
+ const after = String(await page.evaluate(saveDiagnostics).catch(() => null)).slice(0, 600);
23430
+ throw new Error(`\u64AD\u5BA2: \u4FDD\u5B58\u5931\u8D25 \u2014 dispatch=${dispatched} before=${saveBefore} after=${after}`);
23431
+ }
23432
+ }
23433
+ const rowSelector = PODCAST_ROW(materialTitle);
23434
+ const rowProbe = `(() => {
23435
+ const row = [...document.querySelectorAll('.weui-desktop-dialog li.audio_item_wrp, .weui-desktop-dialog div.audio_item_wrp')].find((r) => (r.textContent ?? '').includes(${JSON.stringify(materialTitle)}));
23436
+ return row ? (row.textContent ?? '') : null;
23437
+ })()`;
23438
+ const materialReady = await waitUntil(async () => {
23439
+ const rowText = await page.evaluate(rowProbe);
23440
+ return rowText !== null && !/\u8F6C\u7801\u4E2D|\u5BA1\u6838\u4E2D|\u5904\u7406\u4E2D/.test(rowText);
23441
+ }, 15 * 60000);
23442
+ if (!materialReady) {
23443
+ const probeNow = String(await page.evaluate(reuseProbe) ?? "ERR");
23444
+ throw new Error(`\u64AD\u5BA2: \u97F3\u9891\u7D20\u6750 '${materialTitle}' \u672A\u5728 15min \u5185\u5B8C\u6210\u8F6C\u7801/\u5BA1\u6838\uFF0C\u63D2\u5165\u672A\u6267\u884C\uFF08\u53EF\u91CD\u8DD1\uFF09` + ` \u2014 reuse \u7A97\u53E3 [${reuseHistory.join(",")}] \u6700\u8FD1\u8BFB=${probeNow.slice(0, 30)}`);
23445
+ }
23446
+ await clickSelector(page, await findSelector(page, [`${rowSelector} label.audio_item`, rowSelector], "\u64AD\u5BA2\u7D20\u6750 row", deps.stepTimeoutMs), deps.stepTimeoutMs);
23447
+ await clickSelector(page, await findSelector(page, PODCAST_INSERT, "\u63D2\u5165 control", deps.stepTimeoutMs), deps.stepTimeoutMs);
23303
23448
  await awaitSaveBar(page, deps);
23304
- const titlePath = await typeTitle(page, deps);
23305
- await insertBody(page, deps);
23306
- return { warnings: [], titlePath, enrichWarnings: [] };
23449
+ await typePodcastTitle(page, deps);
23450
+ await insertBody(page, deps, PODCAST_BODY);
23451
+ return { warnings: [], titlePath: "mirror-agreed", enrichWarnings: [] };
23307
23452
  }
23308
23453
  async function awaitSaveBar(page, deps) {
23309
23454
  await findSelector(page, SAVE_DRAFT, "\u4FDD\u5B58\u4E3A\u8349\u7A3F control (it appears only after the media is attached)", deps.stepTimeoutMs);
@@ -23355,7 +23500,7 @@ async function saveDraft(input, deps, entry, composed) {
23355
23500
  await sleep(deps.submitSettleMs);
23356
23501
  if (await closeOpenDialogs(entry.editor) !== "closed") {
23357
23502
  residuals += 1;
23358
- residualDialogs.push(await openDialogInventory(entry.editor).catch(() => "unreadable"));
23503
+ residualDialogs.push(await openDialogInventory(entry.editor));
23359
23504
  if (attempts < deps.submitAttempts)
23360
23505
  continue;
23361
23506
  break;
@@ -23378,7 +23523,7 @@ async function saveDraft(input, deps, entry, composed) {
23378
23523
  }
23379
23524
  if (signal === null || control === null) {
23380
23525
  if (control === null)
23381
- return fail(`draft confirmation: a residual modal refused cleanup after ${attempts} attempt(s), ${residuals} refused cleanup(s) (${residualDialogs.join(" | ") || "no inventory"}) \u2014 '\u4FDD\u5B58\u4E3A\u8349\u7A3F' was not clicked through an unresolved overlay (inventory: ${await openDialogInventory(entry.editor).catch(() => "unreadable")})`);
23526
+ return fail(`draft confirmation: a residual modal refused cleanup after ${attempts} attempt(s), ${residuals} refused cleanup(s) (${residualDialogs.join(" | ") || "no inventory"}) \u2014 '\u4FDD\u5B58\u4E3A\u8349\u7A3F' was not clicked through an unresolved overlay (inventory: ${await openDialogInventory(entry.editor)})`);
23382
23527
  return fail(`draft confirmation: '${SAVE_DRAFT[0]}' was clicked ${attempts}\xD7 but no fresh \u8349\u7A3F\u7BB1 row for '${title}' (its ${DRAFT_STAMP} stamp) was observed within ${deps.draftTimeoutMs}ms (before=${deps.draftBaseline.stamp ?? "none"}, after=${stampAfter ?? "none"}, page=${deps.entry.url()}, frames=${await describeFrames(deps.entry, 5)})`);
23383
23528
  }
23384
23529
  return ResultSchema.parse({
@@ -23504,6 +23649,8 @@ function publicSnapshotIsIncomplete(expected, actual) {
23504
23649
  return true;
23505
23650
  if (!snapshotValueIsEmpty(expected.body) && snapshotValueIsEmpty(actual.body))
23506
23651
  return true;
23652
+ if (actual.body.length < expected.body.length && expected.body.startsWith(actual.body))
23653
+ return true;
23507
23654
  if (expected.media.length > actual.media.length)
23508
23655
  return true;
23509
23656
  if (!snapshotValueIsEmpty(expected.cover) && snapshotValueIsEmpty(actual.cover))
@@ -23517,12 +23664,8 @@ function appmsgIdFromCanonical(value) {
23517
23664
  const canonical = canonicalSavedEditorUrl(value);
23518
23665
  if (canonical === null)
23519
23666
  return null;
23520
- try {
23521
- const appmsgId = new URL(canonical).searchParams.get("appmsgid")?.trim();
23522
- return appmsgId && appmsgId.length > 0 ? appmsgId : null;
23523
- } catch {
23524
- return null;
23525
- }
23667
+ const appmsgId = new URL(canonical).searchParams.get("appmsgid")?.trim();
23668
+ return appmsgId && appmsgId.length > 0 ? appmsgId : null;
23526
23669
  }
23527
23670
  async function waitForPublicEditorReadiness(page, deps) {
23528
23671
  let consecutiveSaved = 0;
@@ -23659,8 +23802,9 @@ async function recoverStaleVersion(deps, entry, saved) {
23659
23802
  }, deps.draftTimeoutMs, deps.pollMs);
23660
23803
  if (!snapshotSettled || latestSnapshot === null)
23661
23804
  return fail("public stale-version recovery: latest editor snapshot was unreadable; no second \u53D1\u8868 click attempted");
23805
+ const latestBody = latestSnapshot.body;
23662
23806
  if (differences.length > 0)
23663
- return fail(`public stale-version recovery: latest editor content mismatch (${differences.join(", ")}); no second \u53D1\u8868 click attempted`);
23807
+ return fail(`public stale-version recovery: latest editor content mismatch (${differences.join(", ")}; body ${latestBody.length}/${saved.snapshot.body.length} chars); no second \u53D1\u8868 click attempted`);
23664
23808
  if (!await waitForPublicEditorReadiness(latestEditor, deps))
23665
23809
  return fail("public stale-version recovery: latest editor did not provide two consecutive recognized readiness probes; no second \u53D1\u8868 click attempted");
23666
23810
  return {
@@ -23716,7 +23860,7 @@ function shouldNotifySubscribers(content) {
23716
23860
  return wechatmp.notifySubscribers !== false;
23717
23861
  }
23718
23862
  async function confirmPublicPublish(page, notifySubscribers, stepTimeoutMs, pollMs) {
23719
- const confirmationTimeoutMs = Math.min(CONFIRM_TIMEOUT_MS, stepTimeoutMs);
23863
+ const confirmationTimeoutMs = stepTimeoutMs;
23720
23864
  const dialog = await findUniqueVisibleSelector(page, PUBLISH_DIALOG, confirmationTimeoutMs, pollMs);
23721
23865
  if (dialog.selector === undefined) {
23722
23866
  if (dialog.reason === "missing") {