@gobing-ai/knowledge-kit 0.1.13 → 0.1.15
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +796 -176
- package/package.json +1 -1
- package/plugins/generations/content-gen/dist/index.js +2 -2
- package/plugins/generations/core-facts-gen/dist/index.js +2 -2
- package/plugins/generations/daily-article-gen/dist/index.js +2 -2
- package/plugins/generations/dailynews-gen/dist/index.js +72 -9
- package/plugins/generations/dailynews-gen/src/index.ts +23 -1
- package/plugins/generations/dailynews-gen/src/script-plan.ts +103 -5
- package/plugins/generations/episode-plan-gen/dist/index.js +2 -2
- package/plugins/generations/gemini-tts/dist/index.js +2 -2
- package/plugins/generations/image-gen/dist/index.js +2 -2
- package/plugins/generations/news-report-gen/dist/index.js +2 -2
- package/plugins/generations/voice-gen/dist/index.js +2 -2
- package/plugins/generations/voxcpm-tts/dist/index.js +2 -2
- package/plugins/ingestions/aihot-ingest/dist/index.js +2 -2
- package/plugins/ingestions/horizon-ingest/dist/index.js +2 -2
- package/plugins/ingestions/last30days-ingest/dist/index.js +2 -2
- package/plugins/ingestions/web-search/dist/index.js +2 -2
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/daily-scheduled-run.ts +53 -5
- package/plugins/kk/scripts/daily-stages.ts +476 -12
- package/plugins/kk/scripts/kk-workflow-stages.ts +20 -4
- package/plugins/kk/skills/content-judge/SKILL.md +5 -4
- package/plugins/kk/skills/content-judge/references/rubrics.md +14 -0
- package/plugins/kk/skills/news-editorial/SKILL.md +122 -0
- package/plugins/kk/skills/news-editorial/references/selection.md +47 -0
- package/plugins/kk/skills/news-editorial/references/style-contract.zh.md +99 -0
- package/plugins/kk/skills/publish/SKILL.md +3 -3
- package/plugins/kk/skills/web-automation/SKILL.md +229 -77
- package/plugins/kk/skills/web-automation/references/browser-launch.md +127 -36
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +4 -6
- package/plugins/kk/workflows/kk-daily-ai-voice3.yaml +183 -222
- package/plugins/kk/workflows/kk-daily-publish3.yaml +16 -8
- package/plugins/publishings/bilibili-pub/dist/index.js +5 -3
- package/plugins/publishings/bilibili-pub/dist/profile-check.js +3 -1
- package/plugins/publishings/cnblogs-pub/dist/index.js +5 -3
- package/plugins/publishings/cnblogs-pub/dist/profile-check.js +3 -1
- package/plugins/publishings/csdn-pub/dist/index.js +5 -3
- package/plugins/publishings/csdn-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/emdash-pub/dist/index.js +2 -2
- package/plugins/publishings/infoq-pub/dist/index.js +5 -3
- package/plugins/publishings/infoq-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/jike-pub/dist/index.js +5 -3
- package/plugins/publishings/jike-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/juejin-pub/dist/index.js +5 -3
- package/plugins/publishings/juejin-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/linkedin-pub/dist/index.js +5 -3
- package/plugins/publishings/linkedin-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/medium-pub/dist/index.js +2 -2
- package/plugins/publishings/podcast-pub/dist/index.js +147 -4
- package/plugins/publishings/podcast-pub/src/index.ts +71 -2
- package/plugins/publishings/podcast-pub/src/map.ts +3 -0
- package/plugins/publishings/podcast-pub/src/transcript.ts +195 -0
- package/plugins/publishings/qiita-pub/dist/index.js +2 -2
- package/plugins/publishings/shipinhao-pub/dist/index.js +5 -3
- package/plugins/publishings/shipinhao-pub/dist/profile-check.js +3 -1
- package/plugins/publishings/sspai-pub/dist/index.js +5 -3
- package/plugins/publishings/sspai-pub/dist/profile-check.js +3 -1
- package/plugins/publishings/substack-pub/dist/index.js +5 -3
- package/plugins/publishings/substack-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/surfdash-pub/dist/index.js +2 -2
- package/plugins/publishings/threads-pub/dist/index.js +2 -2
- package/plugins/publishings/wechatmp-pub/dist/index.js +52 -33
- package/plugins/publishings/wechatmp-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/wechatmp-pub/src/flow.ts +70 -33
- package/plugins/publishings/weibo-pub/dist/index.js +21 -6
- package/plugins/publishings/weibo-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/weibo-pub/src/index.ts +31 -7
- package/plugins/publishings/x-pub/dist/index.js +5 -3
- package/plugins/publishings/x-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/xhs-pub/dist/index.js +5 -3
- package/plugins/publishings/xhs-pub/dist/profile-check.js +5 -3
- package/plugins/publishings/xiaoyuzhou-pub/dist/index.js +5 -3
- package/plugins/publishings/xiaoyuzhou-pub/dist/profile-check.js +3 -1
- package/plugins/publishings/zenn-pub/dist/index.js +2 -2
- package/plugins/kk/scripts/daily-voice-style.zh.md +0 -70
|
@@ -12317,11 +12317,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
12317
12317
|
});
|
|
12318
12318
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
12319
12319
|
if (manifest.browserSession !== undefined) {
|
|
12320
|
-
if (manifest.kind !== "publish") {
|
|
12320
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
12321
12321
|
ctx.addIssue({
|
|
12322
12322
|
code: "custom",
|
|
12323
12323
|
path: ["browserSession"],
|
|
12324
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
12324
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
12325
12325
|
});
|
|
12326
12326
|
}
|
|
12327
12327
|
if (manifest.check === undefined) {
|
|
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
12225
12225
|
});
|
|
12226
12226
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
12227
12227
|
if (manifest.browserSession !== undefined) {
|
|
12228
|
-
if (manifest.kind !== "publish") {
|
|
12228
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
12229
12229
|
ctx.addIssue({
|
|
12230
12230
|
code: "custom",
|
|
12231
12231
|
path: ["browserSession"],
|
|
12232
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
12232
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
12233
12233
|
});
|
|
12234
12234
|
}
|
|
12235
12235
|
if (manifest.check === undefined) {
|
|
@@ -20073,11 +20073,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
20073
20073
|
});
|
|
20074
20074
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
20075
20075
|
if (manifest.browserSession !== undefined) {
|
|
20076
|
-
if (manifest.kind !== "publish") {
|
|
20076
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
20077
20077
|
ctx.addIssue({
|
|
20078
20078
|
code: "custom",
|
|
20079
20079
|
path: ["browserSession"],
|
|
20080
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
20080
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
20081
20081
|
});
|
|
20082
20082
|
}
|
|
20083
20083
|
if (manifest.check === undefined) {
|
|
@@ -20620,10 +20620,12 @@ function sha256Hex(value) {
|
|
|
20620
20620
|
var DEFAULT_BOT_PROFILE_ROOT = join4(homedir4(), ".config", "kk", "browser-profiles");
|
|
20621
20621
|
class BotError extends Error {
|
|
20622
20622
|
code;
|
|
20623
|
-
|
|
20623
|
+
details;
|
|
20624
|
+
constructor(code, message, details = {}) {
|
|
20624
20625
|
super(message);
|
|
20625
20626
|
this.name = "BotError";
|
|
20626
20627
|
this.code = code;
|
|
20628
|
+
this.details = details;
|
|
20627
20629
|
}
|
|
20628
20630
|
}
|
|
20629
20631
|
// ../../packages/publish-harness/src/profile-dir.ts
|
|
@@ -23237,17 +23239,19 @@ async function enrichArticleDraft(page, content, stepTimeoutMs) {
|
|
|
23237
23239
|
const enrichWarnings = await enrichArticle(page, meta);
|
|
23238
23240
|
const audio = audioBlockOf(content);
|
|
23239
23241
|
let audioFailed = false;
|
|
23242
|
+
let coverSeeded = false;
|
|
23240
23243
|
if (audio !== null) {
|
|
23241
|
-
const
|
|
23242
|
-
|
|
23243
|
-
|
|
23244
|
+
const audioResult = await insertAudioMaterial(page, audio);
|
|
23245
|
+
coverSeeded = audioResult.coverSeeded;
|
|
23246
|
+
if (audioResult.warning !== "") {
|
|
23247
|
+
enrichWarnings.push(audioResult.warning);
|
|
23244
23248
|
audioFailed = true;
|
|
23245
23249
|
}
|
|
23246
23250
|
}
|
|
23247
23251
|
const coverWarnings = [];
|
|
23248
23252
|
if (coverSourceOf(content) === "library" && audio !== null) {
|
|
23249
|
-
if (audioFailed) {
|
|
23250
|
-
coverWarnings.push("cover: \u97F3\u9891\u4E0A\u4F20\u672A\u6210\u529F\
|
|
23253
|
+
if (audioFailed && !coverSeeded) {
|
|
23254
|
+
coverWarnings.push("cover: \u97F3\u9891\u4E0A\u4F20\u672A\u6210\u529F\u4E14\u56FE\u7247\u5E93\u5C1A\u65E0\u8BF7\u6C42\u5C01\u9762\uFF0C\u5DF2\u8DF3\u8FC7\u56FE\u7247\u5E93\u5C01\u9762");
|
|
23251
23255
|
} else {
|
|
23252
23256
|
const cover = await setCover(page, "library", { stepTimeoutMs: Math.min(stepTimeoutMs, 8000) }, { binding: audio.coverPath === "" ? undefined : await coverLibraryName(audio.coverPath) });
|
|
23253
23257
|
if (cover !== null)
|
|
@@ -24142,6 +24146,11 @@ function escapeHtml(text) {
|
|
|
24142
24146
|
}
|
|
24143
24147
|
async function insertAudioMaterial(page, input) {
|
|
24144
24148
|
const { title, audioPath, coverPath } = input;
|
|
24149
|
+
let libraryHasCover = false;
|
|
24150
|
+
const result = (warning) => ({
|
|
24151
|
+
warning,
|
|
24152
|
+
coverSeeded: libraryHasCover
|
|
24153
|
+
});
|
|
24145
24154
|
const CARET = `(async () => {
|
|
24146
24155
|
const pm = [...document.querySelectorAll('.ProseMirror')].find((e) => !(e.getAttribute('data-placeholder') ?? '').includes('\u6807\u9898'));
|
|
24147
24156
|
if (!pm || !pm.firstChild) return;
|
|
@@ -24211,11 +24220,11 @@ async function insertAudioMaterial(page, input) {
|
|
|
24211
24220
|
const upload = async () => {
|
|
24212
24221
|
const uploadControl = await trySelectors(page, UPLOAD_AUDIO);
|
|
24213
24222
|
if (!uploadControl.found)
|
|
24214
|
-
return "\u97F3\u9891: \u4E0A\u4F20\u97F3\u9891 control not found in the audio dialog";
|
|
24223
|
+
return result("\u97F3\u9891: \u4E0A\u4F20\u97F3\u9891 control not found in the audio dialog");
|
|
24215
24224
|
await clickSelector(page, uploadControl.selector ?? UPLOAD_AUDIO[0] ?? "text=\u4E0A\u4F20\u97F3\u9891", 8000);
|
|
24216
24225
|
const audioInput = await trySelectors(page, AUDIO_UPLOAD_INPUT, { visible: false });
|
|
24217
24226
|
if (!audioInput.found)
|
|
24218
|
-
return "\u97F3\u9891: no audio file input appeared";
|
|
24227
|
+
return result("\u97F3\u9891: no audio file input appeared");
|
|
24219
24228
|
await uploadFile(asPlaywrightPage(page), audioInput.selector ?? AUDIO_UPLOAD_INPUT.join(", "), audioPath, {
|
|
24220
24229
|
timeoutMs: 60000
|
|
24221
24230
|
});
|
|
@@ -24231,10 +24240,10 @@ async function insertAudioMaterial(page, input) {
|
|
|
24231
24240
|
if (hasChooser) {
|
|
24232
24241
|
const libraryReady = await waitUntil(async () => Boolean(await page.evaluate(`!document.querySelector('#js_image_dialog_list_wrp .weui-desktop-loading')`)), 5000);
|
|
24233
24242
|
if (!libraryReady)
|
|
24234
|
-
return "\u97F3\u9891: \u5C01\u9762\u7D20\u6750\u5E93\u52A0\u8F7D\u672A\u5B8C\u6210\uFF0C\u672A\u4E0A\u4F20\u91CD\u590D\u5C01\u9762";
|
|
24243
|
+
return result("\u97F3\u9891: \u5C01\u9762\u7D20\u6750\u5E93\u52A0\u8F7D\u672A\u5B8C\u6210\uFF0C\u672A\u4E0A\u4F20\u91CD\u590D\u5C01\u9762");
|
|
24235
24244
|
existing = Number(await page.evaluate(`([...document.querySelectorAll('.weui-desktop-img-picker__item')].filter(row => row.offsetWidth > 0 && row.querySelector('.weui-desktop-img-picker__img-title')?.textContent?.trim() === ${JSON.stringify(coverName)})).length`));
|
|
24236
24245
|
if (existing > 1)
|
|
24237
|
-
return "\u97F3\u9891: \u5185\u5BB9\u7ED1\u5B9A\u5C01\u9762\u5B58\u5728\u591A\u4E2A\u540C\u540D\u7D20\u6750\uFF0C\u672A\u731C\u6D4B\u9009\u62E9";
|
|
24246
|
+
return result("\u97F3\u9891: \u5185\u5BB9\u7ED1\u5B9A\u5C01\u9762\u5B58\u5728\u591A\u4E2A\u540C\u540D\u7D20\u6750\uFF0C\u672A\u731C\u6D4B\u9009\u62E9");
|
|
24238
24247
|
}
|
|
24239
24248
|
let uploadPath = coverPath;
|
|
24240
24249
|
let temporaryDir;
|
|
@@ -24263,14 +24272,24 @@ async function insertAudioMaterial(page, input) {
|
|
|
24263
24272
|
return row.classList.contains('selected');
|
|
24264
24273
|
})()`)), 30000);
|
|
24265
24274
|
if (!selected)
|
|
24266
|
-
return "\u97F3\u9891: \u4E0A\u4F20\u5C01\u9762\u672A\u51FA\u73B0\u552F\u4E00\u5DF2\u9009\u4E2D\u7684\u540C\u540D\u56FE\u7247\uFF0C\u672A\u63D0\u4EA4\u5C01\u9762";
|
|
24275
|
+
return result("\u97F3\u9891: \u4E0A\u4F20\u5C01\u9762\u672A\u51FA\u73B0\u552F\u4E00\u5DF2\u9009\u4E2D\u7684\u540C\u540D\u56FE\u7247\uFF0C\u672A\u63D0\u4EA4\u5C01\u9762");
|
|
24276
|
+
libraryHasCover = true;
|
|
24267
24277
|
const next = await findSelector(page, [`${chooser} button:has-text("\u4E0B\u4E00\u6B65"):not(.weui-desktop-btn_disabled)`], "\u97F3\u9891\u5C01\u9762 \u4E0B\u4E00\u6B65", 30000);
|
|
24268
24278
|
await clickSelector(page, next, 8000);
|
|
24269
24279
|
const finish = await findSelector(page, [`${chooser} button:has-text("\u5B8C\u6210"):not(.weui-desktop-btn_disabled)`], "\u97F3\u9891\u5C01\u9762 \u5B8C\u6210", 30000);
|
|
24270
24280
|
await clickSelector(page, finish, 8000);
|
|
24271
|
-
|
|
24272
|
-
if (!closed)
|
|
24273
|
-
|
|
24281
|
+
let closed = await waitUntil(async () => !await page.locator(chooser).first().isVisible(), 25000);
|
|
24282
|
+
if (!closed) {
|
|
24283
|
+
const confirm = await tryFindSelector(page, [`${chooser} button:has-text("\u786E\u5B9A")`], 5000);
|
|
24284
|
+
if (confirm !== undefined) {
|
|
24285
|
+
await clickSelector(page, confirm, 8000);
|
|
24286
|
+
closed = await waitUntil(async () => !await page.locator(chooser).first().isVisible(), 1e4);
|
|
24287
|
+
}
|
|
24288
|
+
}
|
|
24289
|
+
if (!closed) {
|
|
24290
|
+
const inventory = await openDialogInventory(page);
|
|
24291
|
+
return result(`\u97F3\u9891: \u5C01\u9762\u9009\u62E9\u5668\u5B8C\u6210\u540E\u672A\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58\u97F3\u9891${inventory ? ` (dialogs: ${inventory})` : ""}`);
|
|
24292
|
+
}
|
|
24274
24293
|
}
|
|
24275
24294
|
} finally {
|
|
24276
24295
|
if (temporaryDir !== undefined) {
|
|
@@ -24285,10 +24304,10 @@ async function insertAudioMaterial(page, input) {
|
|
|
24285
24304
|
await fillSelector(page, titleInput.selector ?? AUDIO_TITLE_INPUT.join(", "), title);
|
|
24286
24305
|
const agreed = String(await page.evaluate(AGREE));
|
|
24287
24306
|
if (agreed !== "checked")
|
|
24288
|
-
return `\u97F3\u9891: \u670D\u52A1\u89C4\u5219\u52FE\u9009\u5931\u8D25 (${agreed})
|
|
24307
|
+
return result(`\u97F3\u9891: \u670D\u52A1\u89C4\u5219\u52FE\u9009\u5931\u8D25 (${agreed})`);
|
|
24289
24308
|
const save = await findSelector(page, UPLOAD_SAVE.map((selector) => `${selector}:not(.weui-desktop-btn_disabled):not([disabled])`), "\u97F3\u9891\u4E0A\u4F20\u5B8C\u6210\u4E14\u5C01\u9762\u5DF2\u63D0\u4EA4\u540E\u7684\u4FDD\u5B58\u6309\u94AE", 90000);
|
|
24290
24309
|
await clickSelector(page, save, 8000);
|
|
24291
|
-
return
|
|
24310
|
+
return result("");
|
|
24292
24311
|
};
|
|
24293
24312
|
const matchOnce = async () => {
|
|
24294
24313
|
try {
|
|
@@ -24314,57 +24333,57 @@ async function insertAudioMaterial(page, input) {
|
|
|
24314
24333
|
await waitForVisible(page, AUDIO_DIALOG, AUDIO_DIALOG_TIMEOUT_MS);
|
|
24315
24334
|
let match = await awaitMatch();
|
|
24316
24335
|
if (match === "missing") {
|
|
24317
|
-
const
|
|
24318
|
-
if (
|
|
24336
|
+
const uploadResult = await upload();
|
|
24337
|
+
if (uploadResult.warning !== "") {
|
|
24319
24338
|
await page.evaluate(CANCEL);
|
|
24320
|
-
return
|
|
24339
|
+
return result(uploadResult.warning);
|
|
24321
24340
|
}
|
|
24322
24341
|
await waitForVisible(page, AUDIO_DIALOG, AUDIO_DIALOG_TIMEOUT_MS);
|
|
24323
24342
|
match = await awaitMatch();
|
|
24324
24343
|
if (match === "missing") {
|
|
24325
24344
|
await page.evaluate(CANCEL);
|
|
24326
|
-
return `\u97F3\u9891: \u4FDD\u5B58\u540E\u7D20\u6750\u5217\u8868\u672A\u51FA\u73B0\u300C${title}\u300D\uFF0C\u672A\u63D2\u5165\u97F3\u9891
|
|
24345
|
+
return result(`\u97F3\u9891: \u4FDD\u5B58\u540E\u7D20\u6750\u5217\u8868\u672A\u51FA\u73B0\u300C${title}\u300D\uFF0C\u672A\u63D2\u5165\u97F3\u9891`);
|
|
24327
24346
|
}
|
|
24328
24347
|
if (match === "error") {
|
|
24329
24348
|
await page.evaluate(CANCEL);
|
|
24330
|
-
return "\u97F3\u9891: \u4FDD\u5B58\u540E\u7D20\u6750\u5339\u914D\u63A2\u6D4B\u5931\u8D25\uFF0C\u672A\u63D2\u5165\u97F3\u9891";
|
|
24349
|
+
return result("\u97F3\u9891: \u4FDD\u5B58\u540E\u7D20\u6750\u5339\u914D\u63A2\u6D4B\u5931\u8D25\uFF0C\u672A\u63D2\u5165\u97F3\u9891");
|
|
24331
24350
|
}
|
|
24332
24351
|
} else if (match === "error") {
|
|
24333
24352
|
await page.evaluate(CANCEL);
|
|
24334
|
-
return "\u97F3\u9891: \u7D20\u6750\u5339\u914D\u63A2\u6D4B\u5931\u8D25\uFF0C\u672A\u63D2\u5165\u97F3\u9891";
|
|
24353
|
+
return result("\u97F3\u9891: \u7D20\u6750\u5339\u914D\u63A2\u6D4B\u5931\u8D25\uFF0C\u672A\u63D2\u5165\u97F3\u9891");
|
|
24335
24354
|
}
|
|
24336
24355
|
let identity = "";
|
|
24337
24356
|
try {
|
|
24338
24357
|
const parsed = JSON.parse(match);
|
|
24339
24358
|
if (parsed.state !== "checked") {
|
|
24340
24359
|
await page.evaluate(CANCEL);
|
|
24341
|
-
return `\u97F3\u9891: \u7D20\u6750\u300C${title}\u300D${parsed.state === "ambiguous" ? "\u5217\u8868\u5339\u914D\u5230\u591A\u4E2A\u540C\u540D\u6761\u76EE\uFF0C\u8EAB\u4EFD\u4E0D\u552F\u4E00" : parsed.state === "nobox" ? "\u884C\u6CA1\u6709\u52FE\u9009\u6846" : "\u672A\u9009\u4E2D"}\uFF0C\u672A\u63D2\u5165\u97F3\u9891
|
|
24360
|
+
return result(`\u97F3\u9891: \u7D20\u6750\u300C${title}\u300D${parsed.state === "ambiguous" ? "\u5217\u8868\u5339\u914D\u5230\u591A\u4E2A\u540C\u540D\u6761\u76EE\uFF0C\u8EAB\u4EFD\u4E0D\u552F\u4E00" : parsed.state === "nobox" ? "\u884C\u6CA1\u6709\u52FE\u9009\u6846" : "\u672A\u9009\u4E2D"}\uFF0C\u672A\u63D2\u5165\u97F3\u9891`);
|
|
24342
24361
|
}
|
|
24343
24362
|
identity = parsed.identity ?? "";
|
|
24344
24363
|
} catch {
|
|
24345
24364
|
await page.evaluate(CANCEL);
|
|
24346
|
-
return "\u97F3\u9891: \u7D20\u6750\u5339\u914D\u63A2\u6D4B\u8FD4\u56DE\u672A\u77E5\u7ED3\u679C\uFF0C\u672A\u63D2\u5165\u97F3\u9891";
|
|
24365
|
+
return result("\u97F3\u9891: \u7D20\u6750\u5339\u914D\u63A2\u6D4B\u8FD4\u56DE\u672A\u77E5\u7ED3\u679C\uFF0C\u672A\u63D2\u5165\u97F3\u9891");
|
|
24347
24366
|
}
|
|
24348
24367
|
if (await page.evaluate(INSERT) !== true) {
|
|
24349
24368
|
await page.evaluate(CANCEL);
|
|
24350
|
-
return "\u97F3\u9891: \u63D2\u5165\u6309\u94AE\u672A\u627E\u5230\uFF0C\u8BF7\u624B\u52A8\u63D2\u5165";
|
|
24369
|
+
return result("\u97F3\u9891: \u63D2\u5165\u6309\u94AE\u672A\u627E\u5230\uFF0C\u8BF7\u624B\u52A8\u63D2\u5165");
|
|
24351
24370
|
}
|
|
24352
24371
|
await page.waitForTimeout?.(2000);
|
|
24353
24372
|
let verdict;
|
|
24354
24373
|
try {
|
|
24355
24374
|
verdict = JSON.parse(String(await page.evaluate(VERIFY)));
|
|
24356
24375
|
} catch {
|
|
24357
|
-
return "\u97F3\u9891: \u5DF2\u63D2\u5165\u4F46\u65E0\u6CD5\u8BFB\u53D6\u6B63\u6587\u72B6\u6001\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5";
|
|
24376
|
+
return result("\u97F3\u9891: \u5DF2\u63D2\u5165\u4F46\u65E0\u6CD5\u8BFB\u53D6\u6B63\u6587\u72B6\u6001\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5");
|
|
24358
24377
|
}
|
|
24359
24378
|
if (verdict.state === "absent" || verdict.state === "noeditor")
|
|
24360
|
-
return "\u97F3\u9891: \u63D2\u5165\u672A\u751F\u6548\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5";
|
|
24379
|
+
return result("\u97F3\u9891: \u63D2\u5165\u672A\u751F\u6548\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5");
|
|
24361
24380
|
if (verdict.state !== "top")
|
|
24362
|
-
return "\u97F3\u9891: \u5DF2\u63D2\u5165\u4F46\u672A\u5728\u6587\u9996\uFF0C\u8BF7\u624B\u52A8\u8C03\u6574\u4F4D\u7F6E";
|
|
24381
|
+
return result("\u97F3\u9891: \u5DF2\u63D2\u5165\u4F46\u672A\u5728\u6587\u9996\uFF0C\u8BF7\u624B\u52A8\u8C03\u6574\u4F4D\u7F6E");
|
|
24363
24382
|
if (identity === "" || (verdict.identity ?? "") === "" || verdict.identity !== identity)
|
|
24364
|
-
return `\u97F3\u9891: \u5DF2\u63D2\u5165\u6587\u9996\u4F46\u65E0\u6CD5\u6838\u5BF9\u7D20\u6750\u8EAB\u4EFD\uFF08selected=${identity || "\u672A\u8BFB\u5230"} node=${(verdict.identity ?? "").slice(0, 60) || "\u672A\u8BFB\u5230"}\uFF09\uFF0C\u8BF7\u624B\u52A8\u6838\u5BF9
|
|
24365
|
-
return "";
|
|
24383
|
+
return result(`\u97F3\u9891: \u5DF2\u63D2\u5165\u6587\u9996\u4F46\u65E0\u6CD5\u6838\u5BF9\u7D20\u6750\u8EAB\u4EFD\uFF08selected=${identity || "\u672A\u8BFB\u5230"} node=${(verdict.identity ?? "").slice(0, 60) || "\u672A\u8BFB\u5230"}\uFF09\uFF0C\u8BF7\u624B\u52A8\u6838\u5BF9`);
|
|
24384
|
+
return result("");
|
|
24366
24385
|
} catch (error) {
|
|
24367
|
-
return `\u97F3\u9891: ${error instanceof Error ? error.message.slice(0, 120) : "\u81EA\u52A8\u63D2\u5165\u5931\u8D25"}\uFF0C\u8BF7\u624B\u52A8\u63D2\u5165
|
|
24386
|
+
return result(`\u97F3\u9891: ${error instanceof Error ? error.message.slice(0, 120) : "\u81EA\u52A8\u63D2\u5165\u5931\u8D25"}\uFF0C\u8BF7\u624B\u52A8\u63D2\u5165`);
|
|
24368
24387
|
}
|
|
24369
24388
|
}
|
|
24370
24389
|
|
|
@@ -20272,10 +20272,12 @@ function sha256Hex(value) {
|
|
|
20272
20272
|
var DEFAULT_BOT_PROFILE_ROOT = join3(homedir3(), ".config", "kk", "browser-profiles");
|
|
20273
20273
|
class BotError extends Error {
|
|
20274
20274
|
code;
|
|
20275
|
-
|
|
20275
|
+
details;
|
|
20276
|
+
constructor(code, message, details = {}) {
|
|
20276
20277
|
super(message);
|
|
20277
20278
|
this.name = "BotError";
|
|
20278
20279
|
this.code = code;
|
|
20280
|
+
this.details = details;
|
|
20279
20281
|
}
|
|
20280
20282
|
}
|
|
20281
20283
|
// ../../packages/publish-harness/src/index.ts
|
|
@@ -20670,11 +20672,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
20670
20672
|
});
|
|
20671
20673
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
20672
20674
|
if (manifest.browserSession !== undefined) {
|
|
20673
|
-
if (manifest.kind !== "publish") {
|
|
20675
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
20674
20676
|
ctx.addIssue({
|
|
20675
20677
|
code: "custom",
|
|
20676
20678
|
path: ["browserSession"],
|
|
20677
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
20679
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
20678
20680
|
});
|
|
20679
20681
|
}
|
|
20680
20682
|
if (manifest.check === undefined) {
|
|
@@ -1197,10 +1197,12 @@ export async function enrichArticleDraft(
|
|
|
1197
1197
|
const enrichWarnings = await enrichArticle(page, meta);
|
|
1198
1198
|
const audio = audioBlockOf(content);
|
|
1199
1199
|
let audioFailed = false;
|
|
1200
|
+
let coverSeeded = false;
|
|
1200
1201
|
if (audio !== null) {
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1202
|
+
const audioResult = await insertAudioMaterial(page, audio);
|
|
1203
|
+
coverSeeded = audioResult.coverSeeded;
|
|
1204
|
+
if (audioResult.warning !== '') {
|
|
1205
|
+
enrichWarnings.push(audioResult.warning);
|
|
1204
1206
|
audioFailed = true;
|
|
1205
1207
|
}
|
|
1206
1208
|
}
|
|
@@ -1209,8 +1211,8 @@ export async function enrichArticleDraft(
|
|
|
1209
1211
|
// leaves the library without the requested cover, so the dependent picker must not run).
|
|
1210
1212
|
const coverWarnings: string[] = [];
|
|
1211
1213
|
if (coverSourceOf(content) === 'library' && audio !== null) {
|
|
1212
|
-
if (audioFailed) {
|
|
1213
|
-
coverWarnings.push('cover:
|
|
1214
|
+
if (audioFailed && !coverSeeded) {
|
|
1215
|
+
coverWarnings.push('cover: 音频上传未成功且图片库尚无请求封面,已跳过图片库封面');
|
|
1214
1216
|
} else {
|
|
1215
1217
|
const cover = await setCover(
|
|
1216
1218
|
page,
|
|
@@ -2581,8 +2583,16 @@ function escapeHtml(text: string): string {
|
|
|
2581
2583
|
export async function insertAudioMaterial(
|
|
2582
2584
|
page: WechatPage,
|
|
2583
2585
|
input: { title: string; audioPath: string; coverPath: string },
|
|
2584
|
-
): Promise<string> {
|
|
2586
|
+
): Promise<{ warning: string; coverSeeded: boolean }> {
|
|
2585
2587
|
const { title, audioPath, coverPath } = input;
|
|
2588
|
+
// The library demonstrably holds the episode cover once the picker verified the unique same-name
|
|
2589
|
+
// row (0260 R1 refined 2026-11-09): failures AFTER that point must not suppress the deferred
|
|
2590
|
+
// library cover — the skip guard is only honest for failures BEFORE the cover committed.
|
|
2591
|
+
let libraryHasCover = false;
|
|
2592
|
+
const result = (warning: string): { warning: string; coverSeeded: boolean } => ({
|
|
2593
|
+
warning,
|
|
2594
|
+
coverSeeded: libraryHasCover,
|
|
2595
|
+
});
|
|
2586
2596
|
const CARET = `(async () => {
|
|
2587
2597
|
const pm = [...document.querySelectorAll('.ProseMirror')].find((e) => !(e.getAttribute('data-placeholder') ?? '').includes('标题'));
|
|
2588
2598
|
if (!pm || !pm.firstChild) return;
|
|
@@ -2655,15 +2665,15 @@ export async function insertAudioMaterial(
|
|
|
2655
2665
|
return JSON.stringify({ state: 'top', identity });
|
|
2656
2666
|
})()`;
|
|
2657
2667
|
|
|
2658
|
-
/** Upload the audio + its cover, acknowledge the rules, and 保存. Returns a
|
|
2659
|
-
const upload = async (): Promise<string
|
|
2668
|
+
/** Upload the audio + its cover, acknowledge the rules, and 保存. Returns a structured outcome. */
|
|
2669
|
+
const upload = async (): Promise<{ warning: string; coverSeeded: boolean }> => {
|
|
2660
2670
|
const uploadControl = await trySelectors(page, UPLOAD_AUDIO);
|
|
2661
|
-
if (!uploadControl.found) return '音频: 上传音频 control not found in the audio dialog';
|
|
2671
|
+
if (!uploadControl.found) return result('音频: 上传音频 control not found in the audio dialog');
|
|
2662
2672
|
// Click the winner, never a joined union: `text=…, css…` mixes selector engines and
|
|
2663
2673
|
// Playwright parses the whole string as CSS — zero matches (DOM fixture 0260).
|
|
2664
2674
|
await clickSelector(page, uploadControl.selector ?? UPLOAD_AUDIO[0] ?? 'text=上传音频', 8_000);
|
|
2665
2675
|
const audioInput = await trySelectors(page, AUDIO_UPLOAD_INPUT, { visible: false });
|
|
2666
|
-
if (!audioInput.found) return '音频: no audio file input appeared';
|
|
2676
|
+
if (!audioInput.found) return result('音频: no audio file input appeared');
|
|
2667
2677
|
await uploadFile(asPlaywrightPage(page), audioInput.selector ?? AUDIO_UPLOAD_INPUT.join(', '), audioPath, {
|
|
2668
2678
|
timeoutMs: 60_000,
|
|
2669
2679
|
});
|
|
@@ -2687,13 +2697,13 @@ export async function insertAudioMaterial(
|
|
|
2687
2697
|
),
|
|
2688
2698
|
5_000,
|
|
2689
2699
|
);
|
|
2690
|
-
if (!libraryReady) return '音频: 封面素材库加载未完成,未上传重复封面';
|
|
2700
|
+
if (!libraryReady) return result('音频: 封面素材库加载未完成,未上传重复封面');
|
|
2691
2701
|
existing = Number(
|
|
2692
2702
|
await page.evaluate(
|
|
2693
2703
|
`([...document.querySelectorAll('.weui-desktop-img-picker__item')].filter(row => row.offsetWidth > 0 && row.querySelector('.weui-desktop-img-picker__img-title')?.textContent?.trim() === ${JSON.stringify(coverName)})).length`,
|
|
2694
2704
|
),
|
|
2695
2705
|
);
|
|
2696
|
-
if (existing > 1) return '音频: 内容绑定封面存在多个同名素材,未猜测选择';
|
|
2706
|
+
if (existing > 1) return result('音频: 内容绑定封面存在多个同名素材,未猜测选择');
|
|
2697
2707
|
}
|
|
2698
2708
|
let uploadPath = coverPath;
|
|
2699
2709
|
let temporaryDir: string | undefined;
|
|
@@ -2730,7 +2740,10 @@ export async function insertAudioMaterial(
|
|
|
2730
2740
|
),
|
|
2731
2741
|
30_000,
|
|
2732
2742
|
);
|
|
2733
|
-
if (!selected) return '音频: 上传封面未出现唯一已选中的同名图片,未提交封面';
|
|
2743
|
+
if (!selected) return result('音频: 上传封面未出现唯一已选中的同名图片,未提交封面');
|
|
2744
|
+
// The picker just proved the library holds the unique same-name cover; every
|
|
2745
|
+
// failure past this point leaves the cover in the 图片库 (cover rescue valid).
|
|
2746
|
+
libraryHasCover = true;
|
|
2734
2747
|
const next = await findSelector(
|
|
2735
2748
|
page,
|
|
2736
2749
|
[`${chooser} button:has-text("下一步"):not(.weui-desktop-btn_disabled)`],
|
|
@@ -2745,11 +2758,31 @@ export async function insertAudioMaterial(
|
|
|
2745
2758
|
30_000,
|
|
2746
2759
|
);
|
|
2747
2760
|
await clickSelector(page, finish, 8_000);
|
|
2748
|
-
|
|
2761
|
+
// Hardened like the 播客 walk: 完成 may bounce a crop-confirm page; wait long,
|
|
2762
|
+
// retry via 确定, and only then abandon the audio save.
|
|
2763
|
+
let closed = await waitUntil(
|
|
2749
2764
|
async () => !(await page.locator(chooser).first().isVisible()),
|
|
2750
|
-
|
|
2765
|
+
25_000,
|
|
2751
2766
|
);
|
|
2752
|
-
if (!closed)
|
|
2767
|
+
if (!closed) {
|
|
2768
|
+
const confirm = await tryFindSelector(page, [`${chooser} button:has-text("确定")`], 5_000);
|
|
2769
|
+
if (confirm !== undefined) {
|
|
2770
|
+
await clickSelector(page, confirm, 8_000);
|
|
2771
|
+
closed = await waitUntil(
|
|
2772
|
+
async () => !(await page.locator(chooser).first().isVisible()),
|
|
2773
|
+
10_000,
|
|
2774
|
+
);
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
if (!closed) {
|
|
2778
|
+
// Live 2026-11-09 this stall is real — capture WHAT is on screen (the
|
|
2779
|
+
// confirm dialog may not nest under the chooser selector, which would
|
|
2780
|
+
// explain the 确定 retry missing it) before giving up on the audio save.
|
|
2781
|
+
const inventory = await openDialogInventory(page);
|
|
2782
|
+
return result(
|
|
2783
|
+
`音频: 封面选择器完成后未关闭,未保存音频${inventory ? ` (dialogs: ${inventory})` : ''}`,
|
|
2784
|
+
);
|
|
2785
|
+
}
|
|
2753
2786
|
}
|
|
2754
2787
|
} finally {
|
|
2755
2788
|
if (temporaryDir !== undefined) {
|
|
@@ -2762,7 +2795,7 @@ export async function insertAudioMaterial(
|
|
|
2762
2795
|
const titleInput = await trySelectors(page, AUDIO_TITLE_INPUT);
|
|
2763
2796
|
if (titleInput.found) await fillSelector(page, titleInput.selector ?? AUDIO_TITLE_INPUT.join(', '), title);
|
|
2764
2797
|
const agreed = String(await page.evaluate(AGREE));
|
|
2765
|
-
if (agreed !== 'checked') return `音频: 服务规则勾选失败 (${agreed})
|
|
2798
|
+
if (agreed !== 'checked') return result(`音频: 服务规则勾选失败 (${agreed})`);
|
|
2766
2799
|
const save = await findSelector(
|
|
2767
2800
|
page,
|
|
2768
2801
|
UPLOAD_SAVE.map((selector) => `${selector}:not(.weui-desktop-btn_disabled):not([disabled])`),
|
|
@@ -2770,7 +2803,7 @@ export async function insertAudioMaterial(
|
|
|
2770
2803
|
90_000,
|
|
2771
2804
|
);
|
|
2772
2805
|
await clickSelector(page, save, 8_000);
|
|
2773
|
-
return
|
|
2806
|
+
return result('');
|
|
2774
2807
|
};
|
|
2775
2808
|
|
|
2776
2809
|
/** One MATCH read; a throwing probe stays 'error' (unknown, never treated as missing). */
|
|
@@ -2804,24 +2837,24 @@ export async function insertAudioMaterial(
|
|
|
2804
2837
|
if (match === 'missing') {
|
|
2805
2838
|
// No reusable material: upload one, then POLL until the new row actually exists — never
|
|
2806
2839
|
// assume the upload auto-selected a default row (task 0260 AC2).
|
|
2807
|
-
const
|
|
2808
|
-
if (
|
|
2840
|
+
const uploadResult = await upload();
|
|
2841
|
+
if (uploadResult.warning !== '') {
|
|
2809
2842
|
await page.evaluate(CANCEL);
|
|
2810
|
-
return
|
|
2843
|
+
return result(uploadResult.warning);
|
|
2811
2844
|
}
|
|
2812
2845
|
await waitForVisible(page, AUDIO_DIALOG, AUDIO_DIALOG_TIMEOUT_MS);
|
|
2813
2846
|
match = await awaitMatch();
|
|
2814
2847
|
if (match === 'missing') {
|
|
2815
2848
|
await page.evaluate(CANCEL);
|
|
2816
|
-
return `音频: 保存后素材列表未出现「${title}
|
|
2849
|
+
return result(`音频: 保存后素材列表未出现「${title}」,未插入音频`);
|
|
2817
2850
|
}
|
|
2818
2851
|
if (match === 'error') {
|
|
2819
2852
|
await page.evaluate(CANCEL);
|
|
2820
|
-
return '音频: 保存后素材匹配探测失败,未插入音频';
|
|
2853
|
+
return result('音频: 保存后素材匹配探测失败,未插入音频');
|
|
2821
2854
|
}
|
|
2822
2855
|
} else if (match === 'error') {
|
|
2823
2856
|
await page.evaluate(CANCEL);
|
|
2824
|
-
return '音频: 素材匹配探测失败,未插入音频';
|
|
2857
|
+
return result('音频: 素材匹配探测失败,未插入音频');
|
|
2825
2858
|
}
|
|
2826
2859
|
// Parse the match; anything but a unique ticked row stays a warning (never first-item).
|
|
2827
2860
|
let identity = '';
|
|
@@ -2829,32 +2862,36 @@ export async function insertAudioMaterial(
|
|
|
2829
2862
|
const parsed = JSON.parse(match) as { state?: string; identity?: string };
|
|
2830
2863
|
if (parsed.state !== 'checked') {
|
|
2831
2864
|
await page.evaluate(CANCEL);
|
|
2832
|
-
return
|
|
2865
|
+
return result(
|
|
2866
|
+
`音频: 素材「${title}」${parsed.state === 'ambiguous' ? '列表匹配到多个同名条目,身份不唯一' : parsed.state === 'nobox' ? '行没有勾选框' : '未选中'},未插入音频`,
|
|
2867
|
+
);
|
|
2833
2868
|
}
|
|
2834
2869
|
identity = parsed.identity ?? '';
|
|
2835
2870
|
} catch {
|
|
2836
2871
|
await page.evaluate(CANCEL);
|
|
2837
|
-
return '音频: 素材匹配探测返回未知结果,未插入音频';
|
|
2872
|
+
return result('音频: 素材匹配探测返回未知结果,未插入音频');
|
|
2838
2873
|
}
|
|
2839
2874
|
if ((await page.evaluate(INSERT)) !== true) {
|
|
2840
2875
|
await page.evaluate(CANCEL);
|
|
2841
|
-
return '音频: 插入按钮未找到,请手动插入';
|
|
2876
|
+
return result('音频: 插入按钮未找到,请手动插入');
|
|
2842
2877
|
}
|
|
2843
2878
|
await page.waitForTimeout?.(2_000);
|
|
2844
2879
|
let verdict: { state?: string; identity?: string };
|
|
2845
2880
|
try {
|
|
2846
2881
|
verdict = JSON.parse(String(await page.evaluate(VERIFY))) as { state?: string; identity?: string };
|
|
2847
2882
|
} catch {
|
|
2848
|
-
return '音频: 已插入但无法读取正文状态,请手动检查';
|
|
2883
|
+
return result('音频: 已插入但无法读取正文状态,请手动检查');
|
|
2849
2884
|
}
|
|
2850
|
-
if (verdict.state === 'absent' || verdict.state === 'noeditor') return '音频: 插入未生效,请手动检查';
|
|
2851
|
-
if (verdict.state !== 'top') return '音频: 已插入但未在文首,请手动调整位置';
|
|
2885
|
+
if (verdict.state === 'absent' || verdict.state === 'noeditor') return result('音频: 插入未生效,请手动检查');
|
|
2886
|
+
if (verdict.state !== 'top') return result('音频: 已插入但未在文首,请手动调整位置');
|
|
2852
2887
|
// Identity readback (0260 R2): success requires the selected identity to reappear on the
|
|
2853
2888
|
// inserted node; an unreadable identity is an unverifiable warning, never a silent pass.
|
|
2854
2889
|
if (identity === '' || (verdict.identity ?? '') === '' || verdict.identity !== identity)
|
|
2855
|
-
return
|
|
2856
|
-
|
|
2890
|
+
return result(
|
|
2891
|
+
`音频: 已插入文首但无法核对素材身份(selected=${identity || '未读到'} node=${(verdict.identity ?? '').slice(0, 60) || '未读到'}),请手动核对`,
|
|
2892
|
+
);
|
|
2893
|
+
return result('');
|
|
2857
2894
|
} catch (error) {
|
|
2858
|
-
return `音频: ${error instanceof Error ? error.message.slice(0, 120) : '自动插入失败'}
|
|
2895
|
+
return result(`音频: ${error instanceof Error ? error.message.slice(0, 120) : '自动插入失败'},请手动插入`);
|
|
2859
2896
|
}
|
|
2860
2897
|
}
|
|
@@ -20073,11 +20073,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
20073
20073
|
});
|
|
20074
20074
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
20075
20075
|
if (manifest.browserSession !== undefined) {
|
|
20076
|
-
if (manifest.kind !== "publish") {
|
|
20076
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
20077
20077
|
ctx.addIssue({
|
|
20078
20078
|
code: "custom",
|
|
20079
20079
|
path: ["browserSession"],
|
|
20080
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
20080
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
20081
20081
|
});
|
|
20082
20082
|
}
|
|
20083
20083
|
if (manifest.check === undefined) {
|
|
@@ -20701,10 +20701,12 @@ function sha256Hex(value) {
|
|
|
20701
20701
|
var DEFAULT_BOT_PROFILE_ROOT = join4(homedir4(), ".config", "kk", "browser-profiles");
|
|
20702
20702
|
class BotError extends Error {
|
|
20703
20703
|
code;
|
|
20704
|
-
|
|
20704
|
+
details;
|
|
20705
|
+
constructor(code, message, details = {}) {
|
|
20705
20706
|
super(message);
|
|
20706
20707
|
this.name = "BotError";
|
|
20707
20708
|
this.code = code;
|
|
20709
|
+
this.details = details;
|
|
20708
20710
|
}
|
|
20709
20711
|
}
|
|
20710
20712
|
// ../../packages/publish-harness/src/profile-dir.ts
|
|
@@ -21263,7 +21265,10 @@ class WeiboBrowserTransport {
|
|
|
21263
21265
|
}
|
|
21264
21266
|
async probeCoverAttached(page, selector, baseline) {
|
|
21265
21267
|
const count = await this.countImages(page, selector);
|
|
21266
|
-
|
|
21268
|
+
if (count > baseline)
|
|
21269
|
+
return `cover-attached (${count} images)`;
|
|
21270
|
+
const preview = Number(await page.evaluate(`() => document.querySelectorAll('section:not(:has(.n-modal)) .cover-preview, .cover-preview, img.cover-img').length`));
|
|
21271
|
+
return Number.isFinite(preview) && preview > 0 ? `cover-attached (cover-preview x${preview})` : null;
|
|
21267
21272
|
}
|
|
21268
21273
|
async readToasts(page) {
|
|
21269
21274
|
return parseStringArray(await page.evaluate(toastTextsScript()));
|
|
@@ -21451,7 +21456,13 @@ function openCoverLibraryScript() {
|
|
|
21451
21456
|
tab.click();
|
|
21452
21457
|
}
|
|
21453
21458
|
}
|
|
21454
|
-
for (let i = 0; i <
|
|
21459
|
+
for (let i = 0; i < 30 && !document.querySelector('input[type="file"]'); i += 1) await sleep(200);
|
|
21460
|
+
// The \u56FE\u7247\u5E93 tab lazy-loads (upload button + items mount ~5-8s after the tab click; the fixed
|
|
21461
|
+
// 3s window could race it, and a raced tab leaves fileInputs=0 \u2192 no cover attachment).
|
|
21462
|
+
for (let i = 0; i < 40; i += 1) {
|
|
21463
|
+
if (document.querySelector('.n-modal img, .n-modal input[type="file"]')) break;
|
|
21464
|
+
await sleep(250);
|
|
21465
|
+
}
|
|
21455
21466
|
return true;
|
|
21456
21467
|
})()`;
|
|
21457
21468
|
}
|
|
@@ -21479,7 +21490,11 @@ function confirmCoverModalScript() {
|
|
|
21479
21490
|
}
|
|
21480
21491
|
await sleep(200);
|
|
21481
21492
|
}
|
|
21482
|
-
|
|
21493
|
+
// The \u4E0B\u4E00\u6B65 opens the \u56FE\u7247\u88C1\u526A crop modal (\u4E0A\u4E00\u6B65/\u786E\u5B9A), which takes several seconds to
|
|
21494
|
+
// render \u2014 poll for it before clicking, then wait for the whole modal chain to close.
|
|
21495
|
+
for (let i = 0; i < 40 && !Array.from(document.querySelectorAll('.n-modal button')).find((b) => (b.textContent || '').trim() === '\u786E\u5B9A'); i += 1) {
|
|
21496
|
+
await sleep(250);
|
|
21497
|
+
}
|
|
21483
21498
|
for (let i = 0; i < 15; i += 1) {
|
|
21484
21499
|
const okBtn = Array.from(document.querySelectorAll('.n-modal button')).find(
|
|
21485
21500
|
(b) => (b.textContent || '').trim() === '\u786E\u5B9A' && !b.disabled,
|
|
@@ -20369,10 +20369,12 @@ function normalizeSessionIdentity(value) {
|
|
|
20369
20369
|
}
|
|
20370
20370
|
class BotError extends Error {
|
|
20371
20371
|
code;
|
|
20372
|
-
|
|
20372
|
+
details;
|
|
20373
|
+
constructor(code, message, details = {}) {
|
|
20373
20374
|
super(message);
|
|
20374
20375
|
this.name = "BotError";
|
|
20375
20376
|
this.code = code;
|
|
20377
|
+
this.details = details;
|
|
20376
20378
|
}
|
|
20377
20379
|
}
|
|
20378
20380
|
// ../../packages/publish-harness/src/index.ts
|
|
@@ -20945,11 +20947,11 @@ var PluginManifestSchemaBase = looseObject({
|
|
|
20945
20947
|
});
|
|
20946
20948
|
var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
|
|
20947
20949
|
if (manifest.browserSession !== undefined) {
|
|
20948
|
-
if (manifest.kind !== "publish") {
|
|
20950
|
+
if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
|
|
20949
20951
|
ctx.addIssue({
|
|
20950
20952
|
code: "custom",
|
|
20951
20953
|
path: ["browserSession"],
|
|
20952
|
-
message: `browserSession requires kind "publish", not "${manifest.kind}"`
|
|
20954
|
+
message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
|
|
20953
20955
|
});
|
|
20954
20956
|
}
|
|
20955
20957
|
if (manifest.check === undefined) {
|