@gobing-ai/knowledge-kit 0.1.7 → 0.1.9
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/board/collect/index.js +744 -1107
- package/dist/board/daily-voice/index.js +741 -107
- package/dist/board/itc/index.js +32 -6
- package/dist/index.js +1793 -103
- package/package.json +1 -1
- package/plugins/ingestions/horizon-ingest/dist/index.js +24 -1
- package/plugins/ingestions/horizon-ingest/src/index.ts +34 -0
- package/plugins/kk/config.example.yaml +8 -0
- package/plugins/kk/decisions/extract/ai-news.yaml +7 -1
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/publish-presets/daily-ai-voice.json +123 -0
- package/plugins/kk/schedules/kk-daily-publish3-cn-peak.cron.tmpl +20 -0
- package/plugins/kk/schedules/kk-daily-publish3-overseas.cron.tmpl +17 -0
- package/plugins/kk/scripts/daily-stages.ts +664 -83
- package/plugins/kk/scripts/kk-workflow-stages.ts +11 -1
- package/plugins/kk/scripts/topic-boundary.json +18 -83
- package/plugins/kk/workflows/kk-collect.yaml +2 -0
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +82 -8
- package/plugins/kk/workflows/kk-daily-ai-voice3.yaml +842 -0
- package/plugins/kk/workflows/kk-daily-publish3.yaml +282 -0
- package/plugins/publishings/podcast-pub/README.md +65 -0
- package/plugins/publishings/podcast-pub/dist/index.js +1709 -274
- package/plugins/publishings/podcast-pub/plugin.json +1 -1
- package/plugins/publishings/podcast-pub/src/backfill.ts +465 -0
- package/plugins/publishings/podcast-pub/src/index.ts +211 -34
- package/plugins/publishings/podcast-pub/src/microfeed-client.ts +32 -3
- package/plugins/publishings/podcast-pub/src/seo.ts +1081 -0
- package/plugins/publishings/podcast-pub/src/show-notes.ts +71 -6
- package/plugins/publishings/surfdash-pub/dist/index.js +66 -5
- package/plugins/publishings/surfdash-pub/src/index.ts +94 -10
- package/plugins/publishings/wechatmp-pub/dist/index.js +54 -30
- package/plugins/publishings/wechatmp-pub/dist/profile-check.js +8 -3
- package/plugins/publishings/wechatmp-pub/src/enrich.ts +58 -38
- package/plugins/publishings/wechatmp-pub/src/flow.ts +18 -1
- package/plugins/publishings/wechatmp-pub/src/profile-check.ts +7 -1
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type { Doc } from '@gobing-ai/kk-core';
|
|
15
|
+
import {
|
|
16
|
+
type PlanItem,
|
|
17
|
+
type PodcastSeoConfig,
|
|
18
|
+
SEO_DEFAULTS,
|
|
19
|
+
showNotesSummaryParagraph,
|
|
20
|
+
type TimelineStyle,
|
|
21
|
+
warn,
|
|
22
|
+
} from './seo';
|
|
15
23
|
|
|
16
24
|
/** Escapes text content and attribute values (`&`, `<`, `>`, `"`). */
|
|
17
25
|
function escapeHtml(value: string): string {
|
|
@@ -133,7 +141,7 @@ function isGeneratedTimeline(block: string): boolean {
|
|
|
133
141
|
* input. `ponytail`: no JS — timestamp deep-linking depends on the theme's player
|
|
134
142
|
* API; add when microfeed exposes one.
|
|
135
143
|
*/
|
|
136
|
-
function renderTimelineHtml(docs: Doc[], offsets: number[], articleUrl: string): string {
|
|
144
|
+
function renderTimelineHtml(docs: Doc[], offsets: number[], articleUrl: string, style: TimelineStyle): string {
|
|
137
145
|
const rows = docs
|
|
138
146
|
.map((d, i) => {
|
|
139
147
|
const title = escapeHtml(d.title ?? `条目 ${i + 1}`);
|
|
@@ -152,11 +160,15 @@ function renderTimelineHtml(docs: Doc[], offsets: number[], articleUrl: string):
|
|
|
152
160
|
const articleTail = isHttpUrl(articleUrl)
|
|
153
161
|
? `<p>完整图文版:<a href="${escapeHtml(articleUrl)}" target="_blank" rel="noopener">${escapeHtml('本期完整文章')}</a></p>`
|
|
154
162
|
: `<p>${escapeHtml('本期完整文章')}</p>`;
|
|
163
|
+
const styleBlock = style === 'omit' ? '' : `${TIMELINE_STYLE}\n`;
|
|
164
|
+
// `after` (default) keeps the style inside the markers but after the list, so content_text
|
|
165
|
+
// does not open on CSS. `before` is the pre-D9 position, for a byte-identical legacy render.
|
|
166
|
+
const before = style === 'before' ? styleBlock : '';
|
|
167
|
+
const after = style === 'after' ? styleBlock : '';
|
|
155
168
|
return `<!--kk:timeline-->
|
|
156
|
-
${
|
|
157
|
-
<div class="kk-tl">${rows}
|
|
169
|
+
${before}<div class="kk-tl">${rows}
|
|
158
170
|
</div>
|
|
159
|
-
${articleTail}
|
|
171
|
+
${after}${articleTail}
|
|
160
172
|
<!--/kk:timeline-->`;
|
|
161
173
|
}
|
|
162
174
|
|
|
@@ -277,6 +289,22 @@ export interface ShowNotesRenderOptions {
|
|
|
277
289
|
* matched monotonically against segment transcriptions; otherwise `--:--`.
|
|
278
290
|
*/
|
|
279
291
|
audioSegments?: Array<{ duration?: number; transcription?: string }>;
|
|
292
|
+
/** R4. Omit to keep the default (summary on). `false` reproduces the pre-D9 body. */
|
|
293
|
+
summaryParagraph?: boolean;
|
|
294
|
+
/** R4. `after` moves `<style>` below the timeline; `before` is the legacy position; `omit` drops it. */
|
|
295
|
+
timelineStyle?: TimelineStyle;
|
|
296
|
+
seriesName?: string;
|
|
297
|
+
showName?: string;
|
|
298
|
+
descriptionMin?: number;
|
|
299
|
+
descriptionMax?: number;
|
|
300
|
+
descriptionSource?: PodcastSeoConfig['descriptionSource'];
|
|
301
|
+
descriptionPattern?: string;
|
|
302
|
+
/** Playback seconds for the `(约 N 分钟)` clause. Segment durations are the fallback. */
|
|
303
|
+
durationSeconds?: number;
|
|
304
|
+
/** Link text for the summary cross-link. Falls back to 本期完整文章. */
|
|
305
|
+
surfingTitle?: string;
|
|
306
|
+
refinedDescription?: string;
|
|
307
|
+
summaryClauses?: string[];
|
|
280
308
|
}
|
|
281
309
|
|
|
282
310
|
/** Per-item 1–2-sentence briefing: `metadata.brief` first, body sentences as fallback. */
|
|
@@ -298,7 +326,7 @@ function itemBrief(d: Doc): string {
|
|
|
298
326
|
* a `[来源:<label>](<sourceUri>)` link per item, and the full-article footer.
|
|
299
327
|
* Downstream HTML rendering stays with {@link renderShowNotesHtml}.
|
|
300
328
|
*/
|
|
301
|
-
export function renderShowNotesMarkdown(docs: Doc[], opts: ShowNotesRenderOptions): string {
|
|
329
|
+
export function renderShowNotesMarkdown(docs: Doc[], opts: ShowNotesRenderOptions, warnings?: string[]): string {
|
|
302
330
|
const slugify = (t: string): string => {
|
|
303
331
|
const s = t
|
|
304
332
|
.toLowerCase()
|
|
@@ -323,6 +351,9 @@ export function renderShowNotesMarkdown(docs: Doc[], opts: ShowNotesRenderOption
|
|
|
323
351
|
postSlug.length > 0
|
|
324
352
|
? `${baseUrl}${localePrefix}/posts/${postSlug}`
|
|
325
353
|
: `${baseUrl}/zh/posts/${opts.runDate}-${slugify(opts.title)}`;
|
|
354
|
+
if (opts.briefMode === true && postSlug.length === 0) {
|
|
355
|
+
warn('brief mode requested but ARTICLE_POST_PATH is empty; using legacy layout', warnings);
|
|
356
|
+
}
|
|
326
357
|
const briefMode = opts.briefMode === true && postSlug.length > 0;
|
|
327
358
|
const sourceLabel = (d: Doc): string => {
|
|
328
359
|
const m = d.metadata ?? {};
|
|
@@ -335,10 +366,44 @@ export function renderShowNotesMarkdown(docs: Doc[], opts: ShowNotesRenderOption
|
|
|
335
366
|
};
|
|
336
367
|
const offsets = computeAudioOffsets(docs, opts.audioSegments);
|
|
337
368
|
const lines: string[] = [`# ${opts.title}`, ''];
|
|
369
|
+
const summaryOn = opts.summaryParagraph !== false;
|
|
370
|
+
if (summaryOn) {
|
|
371
|
+
const segmentSeconds = opts.audioSegments?.reduce((sum, segment) => sum + (segment.duration ?? 0), 0);
|
|
372
|
+
const durationSeconds =
|
|
373
|
+
opts.durationSeconds ?? (segmentSeconds && segmentSeconds > 0 ? segmentSeconds : undefined);
|
|
374
|
+
const plan: PlanItem[] = docs.map((doc) => {
|
|
375
|
+
const title = doc.title?.trim() ?? '';
|
|
376
|
+
const brief = itemBrief(doc);
|
|
377
|
+
return brief.length > 0 ? { title, brief } : { title };
|
|
378
|
+
});
|
|
379
|
+
const config: PodcastSeoConfig = {
|
|
380
|
+
...SEO_DEFAULTS,
|
|
381
|
+
...(opts.seriesName ? { seriesName: opts.seriesName } : {}),
|
|
382
|
+
...(opts.showName ? { showName: opts.showName } : {}),
|
|
383
|
+
...(opts.descriptionMin !== undefined ? { descriptionMin: opts.descriptionMin } : {}),
|
|
384
|
+
...(opts.descriptionMax !== undefined ? { descriptionMax: opts.descriptionMax } : {}),
|
|
385
|
+
...(opts.descriptionSource ? { descriptionSource: opts.descriptionSource } : {}),
|
|
386
|
+
...(opts.descriptionPattern ? { descriptionPattern: opts.descriptionPattern } : {}),
|
|
387
|
+
summaryParagraph: true,
|
|
388
|
+
timelineStyle: opts.timelineStyle ?? 'after',
|
|
389
|
+
};
|
|
390
|
+
const summary = showNotesSummaryParagraph({
|
|
391
|
+
config,
|
|
392
|
+
runDate: opts.runDate,
|
|
393
|
+
...(durationSeconds !== undefined ? { durationSeconds } : {}),
|
|
394
|
+
plan,
|
|
395
|
+
...(opts.refinedDescription ? { refinedDescription: opts.refinedDescription } : {}),
|
|
396
|
+
...(opts.summaryClauses ? { summaryClauses: opts.summaryClauses } : {}),
|
|
397
|
+
articleUrl,
|
|
398
|
+
linkText: opts.surfingTitle?.trim() || '本期完整文章',
|
|
399
|
+
});
|
|
400
|
+
for (const line of summary.warnings) warn(line.replace(/^WARN podcast-pub:\s*/, ''), warnings);
|
|
401
|
+
lines.push(summary.markdown, '');
|
|
402
|
+
}
|
|
338
403
|
if (briefMode) {
|
|
339
404
|
// Timeline layout (2026-09-16 feedback): real audio offsets left, title + briefing
|
|
340
405
|
// right, article link last — the whole brief body is one pre-built HTML block.
|
|
341
|
-
lines.push(renderTimelineHtml(docs, offsets, articleUrl), '');
|
|
406
|
+
lines.push(renderTimelineHtml(docs, offsets, articleUrl, opts.timelineStyle ?? 'after'), '');
|
|
342
407
|
} else {
|
|
343
408
|
docs.forEach((d, i) => {
|
|
344
409
|
const body = (d.body ?? '').trim();
|
|
@@ -12473,15 +12473,12 @@ function mapContentToSurfingMarkdown(content, options = {}) {
|
|
|
12473
12473
|
...new Set(rawTags.filter((t) => typeof t === "string" && t.trim().length > 0).map((t) => normalizeTag(t)))
|
|
12474
12474
|
].filter((tag) => tag.length > 0);
|
|
12475
12475
|
const isoDate = options.publishDate ?? new Date().toISOString().slice(0, 10);
|
|
12476
|
-
const firstRefUrl = content.references?.[0]?.url;
|
|
12477
|
-
const canonical = typeof firstRefUrl === "string" ? firstRefUrl : typeof content.metadata?.canonicalUrl === "string" ? content.metadata.canonicalUrl : undefined;
|
|
12478
12476
|
const draft = typeof content.metadata?.published === "boolean" ? !content.metadata.published : false;
|
|
12479
12477
|
const frontmatterObj = {
|
|
12480
12478
|
title,
|
|
12481
12479
|
description: description ?? "",
|
|
12482
12480
|
tags,
|
|
12483
12481
|
publishDate: isoDate,
|
|
12484
|
-
...canonical ? { canonical } : {},
|
|
12485
12482
|
draft,
|
|
12486
12483
|
...options.image ? { image: options.image, og_image: options.image } : {}
|
|
12487
12484
|
};
|
|
@@ -12568,6 +12565,35 @@ function cliErrorText(spawned) {
|
|
|
12568
12565
|
function withEmdashTokenHint(errText) {
|
|
12569
12566
|
return /INVALID_TOKEN|API error 401/.test(errText) ? `${errText} \u2014 hint: regenerate the EmDash token (surfing.salty.vip admin console) and update EMDASH_API_TOKEN in ~/.config/kk/config.yaml` : errText;
|
|
12570
12567
|
}
|
|
12568
|
+
function readRefinedSnapshot(filePath) {
|
|
12569
|
+
if (!existsSync2(filePath))
|
|
12570
|
+
return;
|
|
12571
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
12572
|
+
const block = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
12573
|
+
const fm = block?.[1] ?? "";
|
|
12574
|
+
if (!fm || !/^refined:\s*true$/m.test(fm))
|
|
12575
|
+
return;
|
|
12576
|
+
const read = (key) => {
|
|
12577
|
+
const m = fm.match(new RegExp(`^${key}:\\s*(?:>-?
|
|
12578
|
+
((?:[ \\t]+.*
|
|
12579
|
+
?)+)|(.*))$`, "m"));
|
|
12580
|
+
if (!m)
|
|
12581
|
+
return;
|
|
12582
|
+
const value = (m[1] ?? m[2] ?? "").replace(/\n[ \t]+/g, " ").trim();
|
|
12583
|
+
return value.replace(/^["']|["']$/g, "") || undefined;
|
|
12584
|
+
};
|
|
12585
|
+
return {
|
|
12586
|
+
title: read("title"),
|
|
12587
|
+
seoTitle: read("seo_title"),
|
|
12588
|
+
description: read("description"),
|
|
12589
|
+
canonical: read("canonical")
|
|
12590
|
+
};
|
|
12591
|
+
}
|
|
12592
|
+
function requireRefined(filePath) {
|
|
12593
|
+
if (readRefinedSnapshot(filePath))
|
|
12594
|
+
return;
|
|
12595
|
+
return `surfdash refine step did not run for ${filePath} (no \`refined: true\`): the publishing pipeline is broken \u2014 the post would ship with generator-supplied SEO metadata`;
|
|
12596
|
+
}
|
|
12571
12597
|
async function pushPostGit(surfdashRoot, relPostDir, message) {
|
|
12572
12598
|
return commitPostPaths(surfdashRoot, [relPostDir], message);
|
|
12573
12599
|
}
|
|
@@ -12584,12 +12610,40 @@ async function assertMainBranch(surfdashRoot) {
|
|
|
12584
12610
|
}
|
|
12585
12611
|
return { ok: true };
|
|
12586
12612
|
}
|
|
12613
|
+
async function fastForwardToOrigin(surfdashRoot) {
|
|
12614
|
+
const fetched = await spawnCli(["git", "fetch", "--quiet", "origin", "main"], surfdashRoot);
|
|
12615
|
+
if (fetched.exitCode !== 0)
|
|
12616
|
+
return { ok: true };
|
|
12617
|
+
const counts = await spawnCli(["git", "rev-list", "--left-right", "--count", "origin/main...HEAD"], surfdashRoot);
|
|
12618
|
+
if (counts.exitCode !== 0)
|
|
12619
|
+
return { ok: true };
|
|
12620
|
+
const [behindRaw = "0", aheadRaw = "0"] = counts.stdout.trim().split(/\s+/);
|
|
12621
|
+
const behind = Number(behindRaw);
|
|
12622
|
+
const ahead = Number(aheadRaw);
|
|
12623
|
+
if (!Number.isFinite(behind) || !Number.isFinite(ahead) || behind === 0)
|
|
12624
|
+
return { ok: true };
|
|
12625
|
+
if (ahead > 0) {
|
|
12626
|
+
return {
|
|
12627
|
+
ok: false,
|
|
12628
|
+
error: `surfdash checkout diverged from origin/main (${ahead} local, ${behind} remote commit(s)): reconcile it by hand before publishing`
|
|
12629
|
+
};
|
|
12630
|
+
}
|
|
12631
|
+
const merged = await spawnCli(["git", "merge", "--ff-only", "--quiet", "origin/main"], surfdashRoot);
|
|
12632
|
+
if (merged.exitCode !== 0) {
|
|
12633
|
+
return { ok: false, error: `surfdash fast-forward to origin/main failed: ${cliErrorText(merged)}` };
|
|
12634
|
+
}
|
|
12635
|
+
echoError(`surfdash: fast-forwarded ${behind} commit(s) to origin/main before writing`);
|
|
12636
|
+
return { ok: true };
|
|
12637
|
+
}
|
|
12587
12638
|
async function commitPostPaths(surfdashRoot, relPaths, message, push = true) {
|
|
12588
12639
|
if (relPaths.length === 0)
|
|
12589
12640
|
return { ok: true, hash: "unchanged" };
|
|
12590
12641
|
const branch = await assertMainBranch(surfdashRoot);
|
|
12591
12642
|
if (!branch.ok)
|
|
12592
12643
|
return branch;
|
|
12644
|
+
const base = await fastForwardToOrigin(surfdashRoot);
|
|
12645
|
+
if (!base.ok)
|
|
12646
|
+
return base;
|
|
12593
12647
|
const add = await spawnCli(["git", "add", "--", ...relPaths], surfdashRoot);
|
|
12594
12648
|
if (add.exitCode !== 0)
|
|
12595
12649
|
return { ok: false, error: `surfdash git add failed: ${cliErrorText(add)}` };
|
|
@@ -12843,6 +12897,10 @@ async function publishPost(payload) {
|
|
|
12843
12897
|
if (spawned.exitCode !== 0) {
|
|
12844
12898
|
return fail(`postsurfing CLI failed (exit ${spawned.exitCode}): ${withEmdashTokenHint(cliErrorText(spawned))}`);
|
|
12845
12899
|
}
|
|
12900
|
+
const notRefined = requireRefined(filePath);
|
|
12901
|
+
if (notRefined)
|
|
12902
|
+
return fail(notRefined);
|
|
12903
|
+
const refined = readRefinedSnapshot(filePath);
|
|
12846
12904
|
const baseUrl = (process.env.SURFDASH_URL ?? "https://surfing.salty.vip").replace(/\/$/, "");
|
|
12847
12905
|
const articleUrl = `${baseUrl}${locale === "en" ? "" : `/${locale}`}/posts/${slug}`;
|
|
12848
12906
|
if (process.env.SURFDASH_AUTO_PUSH === "0") {
|
|
@@ -12851,7 +12909,7 @@ async function publishPost(payload) {
|
|
|
12851
12909
|
target: TARGET,
|
|
12852
12910
|
url: articleUrl,
|
|
12853
12911
|
message: "Published via postsurfing CLI (auto-push disabled)",
|
|
12854
|
-
metadata: { postPath: filePath }
|
|
12912
|
+
metadata: { postPath: filePath, refinedTitle: refined?.title, refinedCanonical: refined?.canonical }
|
|
12855
12913
|
});
|
|
12856
12914
|
}
|
|
12857
12915
|
const relPostDir = join2("content", "posts", "articles", locale, slug);
|
|
@@ -12864,7 +12922,7 @@ async function publishPost(payload) {
|
|
|
12864
12922
|
target: TARGET,
|
|
12865
12923
|
url: articleUrl,
|
|
12866
12924
|
message: live ? "Published, committed, pushed, and live on the site" : "Published and pushed; URL not live within the verify window \u2014 check the surfdash deploy workflow",
|
|
12867
|
-
metadata: { postPath: filePath, gitCommit: pushed.hash, live }
|
|
12925
|
+
metadata: { postPath: filePath, gitCommit: pushed.hash, live, refinedTitle: refined?.title }
|
|
12868
12926
|
});
|
|
12869
12927
|
} catch (err) {
|
|
12870
12928
|
return fail(`Postsurfing transport error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -12944,6 +13002,7 @@ export {
|
|
|
12944
13002
|
PostsurfingFileCliTransport,
|
|
12945
13003
|
awaitArticleLive,
|
|
12946
13004
|
commitPostPaths,
|
|
13005
|
+
fastForwardToOrigin,
|
|
12947
13006
|
getPublishTransport,
|
|
12948
13007
|
main2 as main,
|
|
12949
13008
|
mapContentToSurfingMarkdown,
|
|
@@ -12951,6 +13010,8 @@ export {
|
|
|
12951
13010
|
normalizeTag,
|
|
12952
13011
|
processPublishIO,
|
|
12953
13012
|
pushPostGit,
|
|
13013
|
+
readRefinedSnapshot,
|
|
13014
|
+
requireRefined,
|
|
12954
13015
|
slugify2 as slugify,
|
|
12955
13016
|
withEmdashTokenHint
|
|
12956
13017
|
};
|
|
@@ -120,23 +120,22 @@ export function mapContentToSurfingMarkdown(content: Content, options: MapConten
|
|
|
120
120
|
].filter((tag) => tag.length > 0);
|
|
121
121
|
|
|
122
122
|
const isoDate = options.publishDate ?? new Date().toISOString().slice(0, 10);
|
|
123
|
-
const firstRefUrl = content.references?.[0]?.url;
|
|
124
|
-
const canonical =
|
|
125
|
-
typeof firstRefUrl === 'string'
|
|
126
|
-
? firstRefUrl
|
|
127
|
-
: typeof content.metadata?.canonicalUrl === 'string'
|
|
128
|
-
? content.metadata.canonicalUrl
|
|
129
|
-
: undefined;
|
|
130
123
|
const draft = typeof content.metadata?.published === 'boolean' ? !content.metadata.published : false;
|
|
131
124
|
|
|
132
125
|
// Strict surfdash PostSchema (surfdash/src/content/schema.ts): publishDate (ISO date) is
|
|
133
126
|
// required; unknown keys (`date`, `canonical_url`, `published`) are rejected.
|
|
127
|
+
//
|
|
128
|
+
// `canonical` is deliberately NOT written here. The canonical URL is the site's own route
|
|
129
|
+
// for this slug, which only the site can compute (locale prefix + collection segment); the
|
|
130
|
+
// previous `references[0].url` fallback pointed the canonical at an unrelated *external*
|
|
131
|
+
// source and would have dropped the post out of the sitemap if surfdash's refine step had
|
|
132
|
+
// not overwritten it. See docs/00_ADR.md ADR-008: the generator supplies content, the site
|
|
133
|
+
// supplies identity.
|
|
134
134
|
const frontmatterObj: Record<string, unknown> = {
|
|
135
135
|
title,
|
|
136
136
|
description: description ?? '',
|
|
137
137
|
tags,
|
|
138
138
|
publishDate: isoDate,
|
|
139
|
-
...(canonical ? { canonical } : {}),
|
|
140
139
|
draft,
|
|
141
140
|
...(options.image ? { image: options.image, og_image: options.image } : {}),
|
|
142
141
|
};
|
|
@@ -273,6 +272,49 @@ export function withEmdashTokenHint(errText: string): string {
|
|
|
273
272
|
: errText;
|
|
274
273
|
}
|
|
275
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Post-conditions the site guarantees after its publishing pipeline ran.
|
|
277
|
+
*
|
|
278
|
+
* The publisher does not derive SEO metadata any more (ADR-008): surfdash's refine step owns
|
|
279
|
+
* `refined`, `seo_title`, `canonical` and the digest title/description. Verifying the marker
|
|
280
|
+
* here turns a silently-regressed site pipeline into a loud publisher failure instead of a post
|
|
281
|
+
* that ships with a date-only title — which is exactly how the 2026-10-21 regression went
|
|
282
|
+
* unnoticed.
|
|
283
|
+
*/
|
|
284
|
+
export interface RefinedSnapshot {
|
|
285
|
+
title?: string;
|
|
286
|
+
seoTitle?: string;
|
|
287
|
+
description?: string;
|
|
288
|
+
canonical?: string;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Reads the frontmatter scalar fields the site owns; undefined when refine never ran. */
|
|
292
|
+
export function readRefinedSnapshot(filePath: string): RefinedSnapshot | undefined {
|
|
293
|
+
if (!existsSync(filePath)) return undefined;
|
|
294
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
295
|
+
const block = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
296
|
+
const fm = block?.[1] ?? '';
|
|
297
|
+
if (!fm || !/^refined:\s*true$/m.test(fm)) return undefined;
|
|
298
|
+
const read = (key: string): string | undefined => {
|
|
299
|
+
const m = fm.match(new RegExp(`^${key}:\\s*(?:>-?\n((?:[ \\t]+.*\n?)+)|(.*))$`, 'm'));
|
|
300
|
+
if (!m) return undefined;
|
|
301
|
+
const value = (m[1] ?? m[2] ?? '').replace(/\n[ \t]+/g, ' ').trim();
|
|
302
|
+
return value.replace(/^["']|["']$/g, '') || undefined;
|
|
303
|
+
};
|
|
304
|
+
return {
|
|
305
|
+
title: read('title'),
|
|
306
|
+
seoTitle: read('seo_title'),
|
|
307
|
+
description: read('description'),
|
|
308
|
+
canonical: read('canonical'),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Error text when the site pipeline did not mark the post refined, else undefined. */
|
|
313
|
+
export function requireRefined(filePath: string): string | undefined {
|
|
314
|
+
if (readRefinedSnapshot(filePath)) return undefined;
|
|
315
|
+
return `surfdash refine step did not run for ${filePath} (no \`refined: true\`): the publishing pipeline is broken — the post would ship with generator-supplied SEO metadata`;
|
|
316
|
+
}
|
|
317
|
+
|
|
276
318
|
/** Outcome of {@link pushPostGit} — the union keeps fail-loud errors typed at the call site. */
|
|
277
319
|
export type GitPushOutcome = { ok: true; hash: string } | { ok: false; error: string };
|
|
278
320
|
|
|
@@ -300,6 +342,41 @@ async function assertMainBranch(surfdashRoot: string): Promise<{ ok: true } | {
|
|
|
300
342
|
return { ok: true };
|
|
301
343
|
}
|
|
302
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Fast-forward the checkout onto `origin/main` before anything is written (2026-10-22).
|
|
347
|
+
*
|
|
348
|
+
* Three consecutive publish days failed with `! [rejected] main -> main (fetch first)`: this
|
|
349
|
+
* checkout sat behind a remote another machine had pushed to, so the publish commit landed on a
|
|
350
|
+
* stale base and the push was rejected — after the article had already been written and committed,
|
|
351
|
+
* and after the podcast episode had already published, so the run closed `partial`/`failed` while a
|
|
352
|
+
* real episode was live. A fast-forward is lossless (HEAD moves only when local carries no commit of
|
|
353
|
+
* its own), which is exactly the case here; a DIVERGED checkout is the operator's call and fails
|
|
354
|
+
* loud with both counts. An unreachable remote is not fatal: the fetch error is swallowed so the
|
|
355
|
+
* push below reports the real reason.
|
|
356
|
+
*/
|
|
357
|
+
export async function fastForwardToOrigin(surfdashRoot: string): Promise<{ ok: true } | { ok: false; error: string }> {
|
|
358
|
+
const fetched = await spawnCli(['git', 'fetch', '--quiet', 'origin', 'main'], surfdashRoot);
|
|
359
|
+
if (fetched.exitCode !== 0) return { ok: true };
|
|
360
|
+
const counts = await spawnCli(['git', 'rev-list', '--left-right', '--count', 'origin/main...HEAD'], surfdashRoot);
|
|
361
|
+
if (counts.exitCode !== 0) return { ok: true };
|
|
362
|
+
const [behindRaw = '0', aheadRaw = '0'] = counts.stdout.trim().split(/\s+/);
|
|
363
|
+
const behind = Number(behindRaw);
|
|
364
|
+
const ahead = Number(aheadRaw);
|
|
365
|
+
if (!Number.isFinite(behind) || !Number.isFinite(ahead) || behind === 0) return { ok: true };
|
|
366
|
+
if (ahead > 0) {
|
|
367
|
+
return {
|
|
368
|
+
ok: false,
|
|
369
|
+
error: `surfdash checkout diverged from origin/main (${ahead} local, ${behind} remote commit(s)): reconcile it by hand before publishing`,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const merged = await spawnCli(['git', 'merge', '--ff-only', '--quiet', 'origin/main'], surfdashRoot);
|
|
373
|
+
if (merged.exitCode !== 0) {
|
|
374
|
+
return { ok: false, error: `surfdash fast-forward to origin/main failed: ${cliErrorText(merged)}` };
|
|
375
|
+
}
|
|
376
|
+
echoError(`surfdash: fast-forwarded ${behind} commit(s) to origin/main before writing`);
|
|
377
|
+
return { ok: true };
|
|
378
|
+
}
|
|
379
|
+
|
|
303
380
|
/**
|
|
304
381
|
* Commits several paths of the surfdash checkout and pushes them to `main` — the plural form of
|
|
305
382
|
* {@link pushPostGit} the post-patch needs (it writes the posts and any copied cover). Same
|
|
@@ -315,6 +392,8 @@ export async function commitPostPaths(
|
|
|
315
392
|
if (relPaths.length === 0) return { ok: true, hash: 'unchanged' };
|
|
316
393
|
const branch = await assertMainBranch(surfdashRoot);
|
|
317
394
|
if (!branch.ok) return branch;
|
|
395
|
+
const base = await fastForwardToOrigin(surfdashRoot);
|
|
396
|
+
if (!base.ok) return base;
|
|
318
397
|
const add = await spawnCli(['git', 'add', '--', ...relPaths], surfdashRoot);
|
|
319
398
|
if (add.exitCode !== 0) return { ok: false, error: `surfdash git add failed: ${cliErrorText(add)}` };
|
|
320
399
|
const staged = await spawnCli(['git', 'diff', '--cached', '--quiet', '--', ...relPaths], surfdashRoot);
|
|
@@ -653,6 +732,11 @@ async function publishPost(payload: PublishTransportPayload): Promise<Result> {
|
|
|
653
732
|
);
|
|
654
733
|
}
|
|
655
734
|
|
|
735
|
+
// Contract check (ADR-008): the site, not this plugin, owns SEO metadata.
|
|
736
|
+
const notRefined = requireRefined(filePath);
|
|
737
|
+
if (notRefined) return fail(notRefined);
|
|
738
|
+
const refined = readRefinedSnapshot(filePath);
|
|
739
|
+
|
|
656
740
|
// Deploy seam: commit + push the post so deploy.yml builds it, then wait for
|
|
657
741
|
// the live URL — downstream show-notes advertise a real page, not a 404.
|
|
658
742
|
// Tests (and offline runs) opt out via SURFDASH_AUTO_PUSH=0.
|
|
@@ -669,7 +753,7 @@ async function publishPost(payload: PublishTransportPayload): Promise<Result> {
|
|
|
669
753
|
message: 'Published via postsurfing CLI (auto-push disabled)',
|
|
670
754
|
// Absolute post path lets downstream steps (locale translation + CMS sync)
|
|
671
755
|
// derive the surfdash checkout root without extra configuration.
|
|
672
|
-
metadata: { postPath: filePath },
|
|
756
|
+
metadata: { postPath: filePath, refinedTitle: refined?.title, refinedCanonical: refined?.canonical },
|
|
673
757
|
});
|
|
674
758
|
}
|
|
675
759
|
const relPostDir = join('content', 'posts', 'articles', locale, slug);
|
|
@@ -684,7 +768,7 @@ async function publishPost(payload: PublishTransportPayload): Promise<Result> {
|
|
|
684
768
|
message: live
|
|
685
769
|
? 'Published, committed, pushed, and live on the site'
|
|
686
770
|
: 'Published and pushed; URL not live within the verify window — check the surfdash deploy workflow',
|
|
687
|
-
metadata: { postPath: filePath, gitCommit: pushed.hash, live },
|
|
771
|
+
metadata: { postPath: filePath, gitCommit: pushed.hash, live, refinedTitle: refined?.title },
|
|
688
772
|
});
|
|
689
773
|
} catch (err: unknown) {
|
|
690
774
|
return fail(`Postsurfing transport error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -22166,12 +22166,7 @@ async function waitForVisible(page, selector, timeoutMs, opts = {}) {
|
|
|
22166
22166
|
// ../../plugins/publishings/wechatmp-pub/src/enrich.ts
|
|
22167
22167
|
var DIALOG = ".weui-desktop-dialog:visible";
|
|
22168
22168
|
var CONFIRM = `${DIALOG} button:has-text("\u786E\u8BA4"), ${DIALOG} button:has-text("\u786E\u5B9A")`;
|
|
22169
|
-
var ROW_ORIGINAL = [
|
|
22170
|
-
".setting-group__switch.js_original_apply.js_edit_ori",
|
|
22171
|
-
".setting-group__switch.js_edit_ori",
|
|
22172
|
-
".js_edit_ori",
|
|
22173
|
-
"text=\u539F\u521B"
|
|
22174
|
-
];
|
|
22169
|
+
var ROW_ORIGINAL = ["#js_original .setting-group__content-info", "#js_original .setting-group__title"];
|
|
22175
22170
|
var ROW_REWARD = [
|
|
22176
22171
|
".setting-group__switch.js_reward_open",
|
|
22177
22172
|
".js_reward_open",
|
|
@@ -22180,18 +22175,28 @@ var ROW_REWARD = [
|
|
|
22180
22175
|
"text=\u8D5E\u8D4F"
|
|
22181
22176
|
];
|
|
22182
22177
|
var ROW_COLLECTION = [".allow_click_opr.js_article_tags_label", "text=\u5408\u96C6"];
|
|
22183
|
-
var ROW_URL = [".
|
|
22184
|
-
var ROW_CLAIM = ["#js_claim_source_area .
|
|
22178
|
+
var ROW_URL = ["#js_article_url_area .js_article_url_allow_click"];
|
|
22179
|
+
var ROW_CLAIM = ["#js_claim_source_area .allow_click_opr"];
|
|
22185
22180
|
var DIALOG_CONFIRM = CONFIRM;
|
|
22181
|
+
var ORIGINAL_CONFIRM = `${DIALOG} button:text-is("\u786E\u5B9A")`;
|
|
22182
|
+
var CLAIM_CONFIRM = `${DIALOG} button:text-is("\u786E\u8BA4")`;
|
|
22186
22183
|
var TAG_INPUT = 'input[placeholder*="\u5408\u96C6"]';
|
|
22187
22184
|
var REWARD_ACCOUNT = [
|
|
22188
22185
|
`${DIALOG} input[placeholder*="\u8D5E\u8D4F"]`,
|
|
22189
22186
|
`${DIALOG} input[placeholder*="\u8D26\u6237"]`,
|
|
22190
22187
|
`${DIALOG} input.frm_input`
|
|
22191
22188
|
];
|
|
22192
|
-
var
|
|
22189
|
+
var URL_POPOVER = ".popover_inner:has(.popover-article-setting__content):visible";
|
|
22190
|
+
var URL_INPUT = [`${URL_POPOVER} input.js_url[name="source_url"]`];
|
|
22191
|
+
var URL_CONFIRM = `${URL_POPOVER} a.jsPopoverBt:text-is("\u786E\u5B9A")`;
|
|
22192
|
+
var URL_CANCEL = `${URL_POPOVER} a.jsPopoverBt:text-is("\u53D6\u6D88")`;
|
|
22193
|
+
var URL_COMMITTED = `(() => {
|
|
22194
|
+
const area = document.querySelector('#js_article_url_area');
|
|
22195
|
+
const checkbox = area?.querySelector('input.js_url_checkbox');
|
|
22196
|
+
return checkbox?.checked === true ? area.querySelector('.article_url_setting')?.textContent ?? null : null;
|
|
22197
|
+
})()`;
|
|
22193
22198
|
var ORIGINAL_DECLARATION = `${DIALOG} label:has(.js_original_type_radio):has-text("\u6587\u5B57\u539F\u521B")`;
|
|
22194
|
-
var ORIGINAL_AGREEMENT = `${DIALOG} .original_agreement`;
|
|
22199
|
+
var ORIGINAL_AGREEMENT = `${DIALOG} label.original_agreement:has(input[type="checkbox"]:not(:checked))`;
|
|
22195
22200
|
var COLLECTION_SETTLE_MS = 1200;
|
|
22196
22201
|
var STEP_RETRY_SETTLE_MS = 1000;
|
|
22197
22202
|
var SWEEP_SETTLE_MS = 400;
|
|
@@ -22203,7 +22208,8 @@ function norm(value) {
|
|
|
22203
22208
|
}
|
|
22204
22209
|
var COMMITTED = {
|
|
22205
22210
|
original: `(() => {
|
|
22206
|
-
const el = document.
|
|
22211
|
+
const el = [...document.querySelectorAll('#js_original input.weui-desktop-switch__input')]
|
|
22212
|
+
.find(input => input.parentElement?.getClientRects().length > 0);
|
|
22207
22213
|
return el ? el.checked === true : null;
|
|
22208
22214
|
})()`,
|
|
22209
22215
|
reward: `(() => {
|
|
@@ -22234,7 +22240,7 @@ async function enrichArticle(page, meta) {
|
|
|
22234
22240
|
const str = (key) => typeof meta[key] === "string" ? meta[key] : "";
|
|
22235
22241
|
const on = (key) => meta[key] === true;
|
|
22236
22242
|
const sweep = async () => {
|
|
22237
|
-
const cancel = await trySelectors(page, ['button:has-text("\u53D6\u6D88")']);
|
|
22243
|
+
const cancel = await trySelectors(page, ['button:has-text("\u53D6\u6D88")', URL_CANCEL]);
|
|
22238
22244
|
if (cancel.found) {
|
|
22239
22245
|
try {
|
|
22240
22246
|
await page.locator(cancel.selector ?? "").first().click({ timeout: 2000 });
|
|
@@ -22305,7 +22311,7 @@ async function enrichArticle(page, meta) {
|
|
|
22305
22311
|
if (agreement.found) {
|
|
22306
22312
|
await clickSelector(page, ORIGINAL_AGREEMENT, 3000);
|
|
22307
22313
|
}
|
|
22308
|
-
await clickSelector(page,
|
|
22314
|
+
await clickSelector(page, ORIGINAL_CONFIRM, 8000);
|
|
22309
22315
|
});
|
|
22310
22316
|
if (outcome !== "capability" && await readChecked(page, COMMITTED.original) !== true && !await residual(name)) {
|
|
22311
22317
|
warnings.push(`${name}: \u539F\u521B\u58F0\u660E\u672A\u751F\u6548\uFF0C\u8BF7\u624B\u52A8\u8BBE\u7F6E`);
|
|
@@ -22358,23 +22364,32 @@ async function enrichArticle(page, meta) {
|
|
|
22358
22364
|
const originalUrl = str("originalUrl");
|
|
22359
22365
|
if (originalUrl !== "") {
|
|
22360
22366
|
const name = "\u539F\u6587\u94FE\u63A5";
|
|
22361
|
-
const
|
|
22367
|
+
const readUrl = async () => {
|
|
22368
|
+
try {
|
|
22369
|
+
return norm(await page.evaluate(URL_COMMITTED));
|
|
22370
|
+
} catch {
|
|
22371
|
+
return "";
|
|
22372
|
+
}
|
|
22373
|
+
};
|
|
22374
|
+
const urlRow = await readUrl() === norm(originalUrl) ? "committed" : await tryFindSelector(page, ROW_URL, 2000);
|
|
22362
22375
|
if (urlRow === undefined) {
|
|
22363
22376
|
warnings.push(`${name}: \u884C\u4E0D\u5B58\u5728\uFF08\u5F53\u524D\u516C\u4F17\u53F7\u4E0D\u652F\u6301\uFF09\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\u6216\u79FB\u9664 originalUrl`);
|
|
22364
|
-
} else {
|
|
22377
|
+
} else if (urlRow !== "committed") {
|
|
22365
22378
|
await step(name, async () => {
|
|
22379
|
+
if (await readUrl() === norm(originalUrl))
|
|
22380
|
+
return;
|
|
22366
22381
|
await openRow(ROW_URL, "\u539F\u6587\u94FE\u63A5");
|
|
22367
22382
|
const field = await trySelectors(page, URL_INPUT);
|
|
22368
22383
|
if (!field.found)
|
|
22369
|
-
throw new Error("no URL field in the \u539F\u6587\u94FE\u63A5
|
|
22384
|
+
throw new Error("no URL field in the \u539F\u6587\u94FE\u63A5 popover");
|
|
22370
22385
|
await fillSelector(page, field.selector ?? URL_INPUT.join(", "), originalUrl);
|
|
22371
|
-
await clickSelector(page,
|
|
22386
|
+
await clickSelector(page, URL_CONFIRM, 8000);
|
|
22387
|
+
await page.locator(URL_POPOVER).first().waitFor?.({ state: "hidden", timeout: 8000 });
|
|
22372
22388
|
});
|
|
22373
|
-
await
|
|
22374
|
-
const locator = page.locator(URL_INPUT[0] ?? "").first();
|
|
22375
|
-
const committed = typeof locator.inputValue === "function" ? await locator.inputValue().catch(() => null) : null;
|
|
22376
|
-
if (norm(committed) !== norm(originalUrl))
|
|
22389
|
+
if (await readUrl() !== norm(originalUrl))
|
|
22377
22390
|
warnings.push(`${name}: \u5DF2\u63D0\u4EA4\u4F46\u672A\u8BFB\u53D6\u5230\u5DF2\u4FDD\u5B58\u7684\u94FE\u63A5\uFF0C\u8BF7\u6838\u5BF9`);
|
|
22391
|
+
if ((await trySelectors(page, [URL_POPOVER])).found)
|
|
22392
|
+
await sweep();
|
|
22378
22393
|
}
|
|
22379
22394
|
}
|
|
22380
22395
|
const claimSource = str("claimSource");
|
|
@@ -22390,17 +22405,22 @@ async function enrichArticle(page, meta) {
|
|
|
22390
22405
|
return null;
|
|
22391
22406
|
}
|
|
22392
22407
|
};
|
|
22408
|
+
let unavailable = false;
|
|
22393
22409
|
if (await claimMatched() !== true) {
|
|
22394
|
-
await step(name, async () => {
|
|
22410
|
+
const outcome = await step(name, async () => {
|
|
22395
22411
|
await openRow(ROW_CLAIM, "\u521B\u4F5C\u6765\u6E90");
|
|
22396
|
-
|
|
22397
|
-
|
|
22398
|
-
|
|
22399
|
-
await
|
|
22412
|
+
await waitForVisible(page, DIALOG, 3000);
|
|
22413
|
+
const stance = `${DIALOG} label:has(input[type="radio"]):has(:text-is(${JSON.stringify(claimSource)}))`;
|
|
22414
|
+
if (await tryFindSelector(page, [stance], 1500) === undefined) {
|
|
22415
|
+
await sweep();
|
|
22416
|
+
throw new CapabilityError(`\u5E73\u53F0\u672A\u63D0\u4F9B\u58F0\u660E\u7C7B\u578B\u300C${claimSource}\u300D\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
22400
22417
|
}
|
|
22418
|
+
await clickSelector(page, stance, 8000);
|
|
22419
|
+
await clickSelector(page, CLAIM_CONFIRM, 8000);
|
|
22401
22420
|
});
|
|
22421
|
+
unavailable = outcome === "capability";
|
|
22402
22422
|
}
|
|
22403
|
-
if (await claimMatched() !== true && !await residual(name)) {
|
|
22423
|
+
if (!unavailable && await claimMatched() !== true && !await residual(name)) {
|
|
22404
22424
|
warnings.push(`${name}: \u672A\u751F\u6548\uFF0C\u8BF7\u624B\u52A8\u8BBE\u7F6E`);
|
|
22405
22425
|
}
|
|
22406
22426
|
}
|
|
@@ -22507,13 +22527,17 @@ var AUDIO_UPLOAD_INPUT = [
|
|
|
22507
22527
|
'.weui-desktop-dialog input[type="file"][accept*="audio"]',
|
|
22508
22528
|
'.weui-desktop-dialog input[type="file"][accept*=".mp3"]',
|
|
22509
22529
|
'.audio_dialog input[type="file"][accept*="audio"]',
|
|
22510
|
-
'input[type="file"][accept*=".mp3"]'
|
|
22530
|
+
'input[type="file"][accept*=".mp3"]',
|
|
22531
|
+
'.weui-desktop-dialog input[type="file"]:not([accept*="image"])',
|
|
22532
|
+
'.audio_dialog input[type="file"]:not([accept*="image"])'
|
|
22511
22533
|
];
|
|
22512
22534
|
var UPLOAD_COVER = ["text=\u4E0A\u4F20\u5C01\u9762", 'button:has-text("\u4E0A\u4F20\u5C01\u9762")'];
|
|
22513
22535
|
var AUDIO_COVER_INPUT = [
|
|
22514
22536
|
'.weui-desktop-dialog input[type="file"][accept*="image/"]',
|
|
22515
22537
|
'.audio_dialog input[type="file"][accept*="image/"]',
|
|
22516
|
-
'input[type="file"][accept*=".png"]'
|
|
22538
|
+
'input[type="file"][accept*=".png"]',
|
|
22539
|
+
'.weui-desktop-dialog input[type="file"][accept*="image"]',
|
|
22540
|
+
'.audio_dialog input[type="file"][accept*="image"]'
|
|
22517
22541
|
];
|
|
22518
22542
|
var AUDIO_TITLE_INPUT = [
|
|
22519
22543
|
'.weui-desktop-dialog input[placeholder*="\u6807\u9898"]',
|
|
@@ -22702,7 +22726,7 @@ async function applyLayout(page, deps) {
|
|
|
22702
22726
|
}
|
|
22703
22727
|
const option = await tryFindSelector(page, LAYOUT_TARGET, 5000);
|
|
22704
22728
|
if (option === undefined) {
|
|
22705
|
-
return "\u4E00\u952E\u6392\u7248:
|
|
22729
|
+
return "\u4E00\u952E\u6392\u7248: the control exists but this build renders no \u5339\u914D\u76EE\u6807\u683C\u5F0F option (measured 2026-10-21 with a body in place) \u2014 layout skipped, apply \u4E00\u952E\u6392\u7248 by hand before publishing";
|
|
22706
22730
|
}
|
|
22707
22731
|
try {
|
|
22708
22732
|
await clickSelector(page, option, 5000);
|
|
@@ -20729,14 +20729,19 @@ var MAX_AGGREGATE_BYTES = 20 * 1024 * 1024;
|
|
|
20729
20729
|
// ../../plugins/publishings/wechatmp-pub/src/enrich.ts
|
|
20730
20730
|
var DIALOG = ".weui-desktop-dialog:visible";
|
|
20731
20731
|
var CONFIRM = `${DIALOG} button:has-text("\u786E\u8BA4"), ${DIALOG} button:has-text("\u786E\u5B9A")`;
|
|
20732
|
+
var ORIGINAL_CONFIRM = `${DIALOG} button:text-is("\u786E\u5B9A")`;
|
|
20733
|
+
var CLAIM_CONFIRM = `${DIALOG} button:text-is("\u786E\u8BA4")`;
|
|
20732
20734
|
var REWARD_ACCOUNT = [
|
|
20733
20735
|
`${DIALOG} input[placeholder*="\u8D5E\u8D4F"]`,
|
|
20734
20736
|
`${DIALOG} input[placeholder*="\u8D26\u6237"]`,
|
|
20735
20737
|
`${DIALOG} input.frm_input`
|
|
20736
20738
|
];
|
|
20737
|
-
var
|
|
20739
|
+
var URL_POPOVER = ".popover_inner:has(.popover-article-setting__content):visible";
|
|
20740
|
+
var URL_INPUT = [`${URL_POPOVER} input.js_url[name="source_url"]`];
|
|
20741
|
+
var URL_CONFIRM = `${URL_POPOVER} a.jsPopoverBt:text-is("\u786E\u5B9A")`;
|
|
20742
|
+
var URL_CANCEL = `${URL_POPOVER} a.jsPopoverBt:text-is("\u53D6\u6D88")`;
|
|
20738
20743
|
var ORIGINAL_DECLARATION = `${DIALOG} label:has(.js_original_type_radio):has-text("\u6587\u5B57\u539F\u521B")`;
|
|
20739
|
-
var ORIGINAL_AGREEMENT = `${DIALOG} .original_agreement`;
|
|
20744
|
+
var ORIGINAL_AGREEMENT = `${DIALOG} label.original_agreement:has(input[type="checkbox"]:not(:checked))`;
|
|
20740
20745
|
|
|
20741
20746
|
// ../../plugins/publishings/wechatmp-pub/src/index.ts
|
|
20742
20747
|
var CHANNEL = TARGET;
|
|
@@ -20828,7 +20833,7 @@ if (false) {}
|
|
|
20828
20833
|
// ../../plugins/publishings/wechatmp-pub/src/profile-check.ts
|
|
20829
20834
|
var USAGE = "usage: wechatmp profile-check [login|check|open] [--profile <dir>] [--url <url>] [--timeout <ms>] [--headed]";
|
|
20830
20835
|
var LOGIN_TIMEOUT_MS = 180000;
|
|
20831
|
-
var PROFILE_OVERHEAD_MS =
|
|
20836
|
+
var PROFILE_OVERHEAD_MS = 25000;
|
|
20832
20837
|
var MIN_READINESS_MS = 1000;
|
|
20833
20838
|
async function main2(argv = process.argv.slice(2)) {
|
|
20834
20839
|
let command;
|