@gobing-ai/knowledge-kit 0.0.37 → 0.1.1
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.css +654 -16
- package/dist/board/collect/index.js +191 -64
- package/dist/board/daily-voice/index.css +679 -12
- package/dist/board/daily-voice/index.js +185 -66
- package/dist/board/itc/index.css +679 -13
- package/dist/board/itc/index.js +188 -66
- package/dist/index.js +2864 -139
- package/package.json +3 -2
- package/plugins/generations/content-gen/dist/index.js +158 -12
- package/plugins/generations/core-facts-gen/dist/index.js +158 -12
- package/plugins/generations/daily-article-gen/dist/index.js +158 -12
- package/plugins/generations/dailynews-gen/dist/index.js +158 -12
- package/plugins/generations/episode-plan-gen/dist/index.js +158 -12
- package/plugins/generations/gemini-tts/README.md +4 -3
- package/plugins/generations/gemini-tts/dist/index.js +158 -12
- package/plugins/generations/image-gen/dist/index.js +158 -12
- package/plugins/generations/news-report-gen/dist/index.js +158 -12
- package/plugins/generations/omni-voice-gen/README.md +15 -4
- package/plugins/generations/omni-voice-gen/profiles.json +1 -2
- package/plugins/generations/voice-gen/dist/index.js +158 -12
- package/plugins/generations/voxcpm-tts/README.md +21 -1
- package/plugins/generations/voxcpm-tts/dist/index.js +173 -13
- package/plugins/generations/voxcpm-tts/scripts/audit-speaker-consistency.py +109 -0
- package/plugins/generations/voxcpm-tts/src/voxcpm-client.ts +28 -1
- package/plugins/ingestions/aihot-ingest/dist/index.js +158 -12
- package/plugins/ingestions/horizon-ingest/dist/index.js +158 -12
- package/plugins/ingestions/last30days-ingest/dist/index.js +158 -12
- package/plugins/ingestions/web-search/dist/index.js +158 -12
- package/plugins/kk/commands/workflow-run.md +56 -18
- package/plugins/kk/decisions/kk-itc.yaml +46 -0
- package/plugins/kk/decisions/kk-seo-keyword.yaml +57 -0
- package/plugins/kk/decisions/kk-seo-page.yaml +230 -0
- package/plugins/kk/decisions/kk-seo-pair.yaml +21 -0
- package/plugins/kk/decisions/kk-seo-site.yaml +90 -0
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/publish-presets/chinese-article.json +14 -0
- package/plugins/kk/publish-presets/technical-article.json +14 -0
- package/plugins/kk/references/smart-seo-attribution.md +85 -0
- package/plugins/kk/scripts/daily-stages.ts +42 -2
- package/plugins/kk/scripts/itc-stages.ts +25 -118
- package/plugins/kk/scripts/kk-workflow-stages.ts +38 -1
- package/plugins/kk/scripts/seo-decisions.ts +491 -0
- package/plugins/kk/scripts/seo-enrich.ts +728 -0
- package/plugins/kk/scripts/seo-facts.ts +610 -0
- package/plugins/kk/scripts/seo-fetch.ts +766 -0
- package/plugins/kk/scripts/seo-report.ts +460 -0
- package/plugins/kk/scripts/seo-rules.ts +1882 -0
- package/plugins/kk/scripts/seo-stages.ts +1044 -0
- package/plugins/kk/skills/article-adapt/SKILL.md +2 -2
- package/plugins/kk/skills/smart-seo/SKILL.md +183 -0
- package/plugins/kk/skills/smart-seo/references/method.md +126 -0
- package/plugins/kk/skills/smart-seo/references/narrative.md +125 -0
- package/plugins/kk/skills/smart-seo/references/operations.md +209 -0
- package/plugins/kk/skills/smart-seo/references/seo-geo-sources.md +90 -0
- package/plugins/kk/workflows/feature-verification.yaml +28 -24
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +85 -17
- package/plugins/kk/workflows/kk-itc-author.yaml +406 -0
- package/plugins/kk/workflows/kk-itc.yaml +208 -682
- package/plugins/kk/workflows/kk-smart-seo.yaml +251 -0
- package/plugins/publishings/bilibili-pub/dist/index.js +21782 -0
- package/plugins/publishings/bilibili-pub/dist/profile-check.js +20410 -0
- package/plugins/publishings/bilibili-pub/package.json +20 -0
- package/plugins/publishings/bilibili-pub/plugin.json +12 -0
- package/plugins/publishings/bilibili-pub/src/flow.ts +1296 -0
- package/plugins/publishings/bilibili-pub/src/index.ts +139 -0
- package/plugins/publishings/bilibili-pub/src/profile-check.ts +19 -0
- package/plugins/publishings/bilibili-pub/src/selectors.ts +222 -0
- package/plugins/publishings/bilibili-pub/tsconfig.json +4 -0
- package/plugins/publishings/cnblogs-pub/dist/index.js +21383 -0
- package/plugins/publishings/cnblogs-pub/dist/profile-check.js +20412 -0
- package/plugins/publishings/cnblogs-pub/package.json +19 -0
- package/plugins/publishings/cnblogs-pub/plugin.json +12 -0
- package/plugins/publishings/cnblogs-pub/src/flow.ts +708 -0
- package/plugins/publishings/cnblogs-pub/src/index.ts +172 -0
- package/plugins/publishings/cnblogs-pub/src/profile-check.ts +24 -0
- package/plugins/publishings/cnblogs-pub/src/selectors.ts +104 -0
- package/plugins/publishings/cnblogs-pub/tsconfig.json +4 -0
- package/plugins/publishings/csdn-pub/dist/index.js +21552 -0
- package/plugins/publishings/csdn-pub/dist/profile-check.js +20963 -0
- package/plugins/publishings/csdn-pub/package.json +19 -0
- package/plugins/publishings/csdn-pub/plugin.json +12 -0
- package/plugins/publishings/csdn-pub/src/index.ts +1178 -0
- package/plugins/publishings/csdn-pub/src/profile-check.ts +23 -0
- package/plugins/publishings/csdn-pub/tsconfig.json +4 -0
- package/plugins/publishings/emdash-pub/dist/index.js +158 -12
- package/plugins/publishings/emdash-pub/plugin.json +22 -1
- package/plugins/publishings/infoq-pub/dist/index.js +160 -12
- package/plugins/publishings/infoq-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/infoq-pub/plugin.json +21 -0
- package/plugins/publishings/jike-pub/dist/index.js +21379 -0
- package/plugins/publishings/jike-pub/dist/profile-check.js +20951 -0
- package/plugins/publishings/jike-pub/package.json +19 -0
- package/plugins/publishings/jike-pub/plugin.json +12 -0
- package/plugins/publishings/jike-pub/src/index.ts +800 -0
- package/plugins/publishings/jike-pub/src/profile-check.ts +21 -0
- package/plugins/publishings/jike-pub/tsconfig.json +4 -0
- package/plugins/publishings/juejin-pub/dist/index.js +160 -12
- package/plugins/publishings/juejin-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/juejin-pub/plugin.json +21 -0
- package/plugins/publishings/medium-pub/dist/index.js +158 -12
- package/plugins/publishings/medium-pub/plugin.json +22 -1
- package/plugins/publishings/podcast-pub/dist/index.js +158 -12
- package/plugins/publishings/qiita-pub/dist/index.js +158 -12
- package/plugins/publishings/qiita-pub/plugin.json +24 -1
- package/plugins/publishings/shipinhao-pub/dist/index.js +21715 -0
- package/plugins/publishings/shipinhao-pub/dist/profile-check.js +20431 -0
- package/plugins/publishings/shipinhao-pub/package.json +19 -0
- package/plugins/publishings/shipinhao-pub/plugin.json +12 -0
- package/plugins/publishings/shipinhao-pub/src/flow.ts +1323 -0
- package/plugins/publishings/shipinhao-pub/src/index.ts +173 -0
- package/plugins/publishings/shipinhao-pub/src/profile-check.ts +25 -0
- package/plugins/publishings/shipinhao-pub/src/selectors.ts +241 -0
- package/plugins/publishings/shipinhao-pub/tsconfig.json +4 -0
- package/plugins/publishings/sspai-pub/dist/index.js +21371 -0
- package/plugins/publishings/sspai-pub/dist/profile-check.js +20414 -0
- package/plugins/publishings/sspai-pub/package.json +19 -0
- package/plugins/publishings/sspai-pub/plugin.json +12 -0
- package/plugins/publishings/sspai-pub/src/flow.ts +624 -0
- package/plugins/publishings/sspai-pub/src/index.ts +167 -0
- package/plugins/publishings/sspai-pub/src/profile-check.ts +25 -0
- package/plugins/publishings/sspai-pub/src/selectors.ts +122 -0
- package/plugins/publishings/sspai-pub/tsconfig.json +4 -0
- package/plugins/publishings/substack-pub/dist/index.js +160 -12
- package/plugins/publishings/substack-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/substack-pub/plugin.json +21 -0
- package/plugins/publishings/surfdash-pub/dist/index.js +158 -12
- package/plugins/publishings/surfdash-pub/plugin.json +22 -1
- package/plugins/publishings/threads-pub/dist/index.js +158 -12
- package/plugins/publishings/wechatmp-pub/dist/index.js +1669 -502
- package/plugins/publishings/wechatmp-pub/dist/profile-check.js +204 -21
- package/plugins/publishings/wechatmp-pub/plugin.json +32 -0
- package/plugins/publishings/wechatmp-pub/src/cgi-draft.ts +540 -0
- package/plugins/publishings/wechatmp-pub/src/cgi-media.ts +380 -0
- package/plugins/publishings/wechatmp-pub/src/cgi.ts +485 -0
- package/plugins/publishings/wechatmp-pub/src/flow.ts +104 -0
- package/plugins/publishings/weibo-pub/dist/index.js +160 -12
- package/plugins/publishings/weibo-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/weibo-pub/plugin.json +35 -0
- package/plugins/publishings/x-pub/dist/index.js +160 -12
- package/plugins/publishings/x-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/x-pub/plugin.json +40 -0
- package/plugins/publishings/xhs-pub/dist/index.js +160 -12
- package/plugins/publishings/xhs-pub/dist/profile-check.js +160 -12
- package/plugins/publishings/xhs-pub/plugin.json +37 -0
- package/plugins/publishings/xiaoyuzhou-pub/dist/index.js +21491 -0
- package/plugins/publishings/xiaoyuzhou-pub/dist/profile-check.js +20417 -0
- package/plugins/publishings/xiaoyuzhou-pub/package.json +19 -0
- package/plugins/publishings/xiaoyuzhou-pub/plugin.json +12 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/flow.ts +826 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/index.ts +174 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/profile-check.ts +26 -0
- package/plugins/publishings/xiaoyuzhou-pub/src/selectors.ts +125 -0
- package/plugins/publishings/xiaoyuzhou-pub/tsconfig.json +4 -0
- package/plugins/publishings/zenn-pub/dist/index.js +158 -12
- package/plugins/publishings/zenn-pub/plugin.json +22 -1
- package/plugins/generations/omni-voice-gen/voices/robin-news.wav +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Smart SEO Attribution & Upstream Review Notice
|
|
2
|
+
|
|
3
|
+
## Upstream Project and License
|
|
4
|
+
|
|
5
|
+
Knowledge Kit Smart SEO (`kk-smart-seo`) adapts and grounds the methodology and rules from the upstream `jev-seo` project.
|
|
6
|
+
|
|
7
|
+
- **Upstream Project:** `jev-seo` (version 0.1.1)
|
|
8
|
+
- **Upstream Commit Snapshot:** `55a184a3b0d09565a4c84268f725a47784e62528`
|
|
9
|
+
- **Upstream Author:** Agrici Daniel
|
|
10
|
+
- **License:** MIT License
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
MIT License
|
|
14
|
+
|
|
15
|
+
Copyright (c) 2026 Agrici Daniel
|
|
16
|
+
|
|
17
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
in the Software without restriction, including without limitation the rights
|
|
20
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
furnished to do so, subject to the following conditions:
|
|
23
|
+
|
|
24
|
+
The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
copies or substantial portions of the Software.
|
|
26
|
+
|
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
SOFTWARE.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architectural & SECUA Audit Linkage
|
|
37
|
+
|
|
38
|
+
The upstream vendor snapshot was fully reviewed in `docs/plans/2026-10-14-smart-seo-vendor-review.md`.
|
|
39
|
+
|
|
40
|
+
Key architectural and security adaptations include:
|
|
41
|
+
1. **Network Trust Boundary (V01, V02):** Replaced unpinned ambient requests with connection-pinned public HTTP(S) transport, DNS resolution validation against private/reserved/multicast ranges, peer address verification, and scoped redirect validation. No browser or Chromium runtime path is imported.
|
|
42
|
+
2. **Resource Boundaries (V03, V04):** Streamed response limit of 2 MiB per response, 40 MiB crawl total, shared request quotas (default 200, max 500) and shared deadline (default 600s, max 1800s).
|
|
43
|
+
3. **Robots & Sitemap Integrity (V04, V05, V06):** Robots.txt fetched first and respects full `Crawl-delay` or marks budget exhaustion; distinguishes absent (404/410), blocked (401/403), and unavailable (429/5xx). Strictly bounded non-expanding XML subset reader rejecting DOCTYPE/entities/compression.
|
|
44
|
+
4. **Distinct URL & Identity Preservation (V06):** Preserves pathname, query parameters, and trailing slashes (`/a` and `/a/` remain distinct resources); fragments stripped.
|
|
45
|
+
5. **Clean Runtime Seam:** Knowledge Kit Smart SEO is implemented as native TypeScript stages on Bun 1.4.3 (`plugins/kk/scripts/seo-*.ts`), importing no vendor Python files or bundled font assets.
|
|
46
|
+
|
|
47
|
+
## Rule Dispositions (52 Rules)
|
|
48
|
+
|
|
49
|
+
All 52 deterministic rules from the vendor snapshot have explicit dispositions:
|
|
50
|
+
- **Native (24 rules):** `redirect_chains`, `links_to_redirects`, `host_temporary_redirect`, `deep_pages`, `title_missing`, `title_duplicate`, `title_length`, `multiple_titles`, `meta_missing`, `meta_duplicate`, `h1_missing`, `h1_multiple`, `heading_skips`, `lang_missing`, `viewport_missing`, `thin_content`, `duplicate_content`, `images_alt`, `images_dimensions`, `jsonld_errors`, `og_missing`, `mixed_content`, `heavy_html`, `generic_anchors`.
|
|
51
|
+
- **Adapted (15 rules):** `robots_blocks_site`, `sitemap_errors`, `sitemap_bad_urls`, `http_errors`, `broken_internal_links`, `noindex`, `canonical_elsewhere`, `canonical_broken`, `soft_404`, `host_variant`, `no_https`, `orphan_pages`, `faq_rich_result_limited`, `hreflang_issues`, `slow_ttfb`.
|
|
52
|
+
- **Informational (11 rules):** `robots_missing`, `sitemap_missing`, `not_in_sitemap`, `canonical_missing`, `js_dependent`, `no_structured_data`, `ai_bots_blocked`, `llms_txt_missing`, `hsts_missing`, `security_headers`, `favicon_missing`.
|
|
53
|
+
- **Deferred (2 rules):** `schema_required`, `broken_external_links`.
|
|
54
|
+
|
|
55
|
+
## Adapted Rubric & Source Attribution (task 0286)
|
|
56
|
+
|
|
57
|
+
The `smart-seo` skill and its references restate **KK-authored** adaptations of the upstream
|
|
58
|
+
methodology. They are not copies of vendor prose, and the following must stay explicit whenever the
|
|
59
|
+
rubric is described or reused:
|
|
60
|
+
|
|
61
|
+
1. **Decision catalogs** (`plugins/kk/decisions/kk-seo-{site,page,pair,keyword}.yaml`, 22 decisions)
|
|
62
|
+
adapt the vendor's decision *descriptions and vocabularies* (business model, page type, search
|
|
63
|
+
intent, page action, 0–3 editorial scores, noul questions). KK additions: an `unclear` choice in
|
|
64
|
+
every choice vocabulary, `keep-or-improve|rewrite|review-consolidation|unclear` instead of
|
|
65
|
+
automatic removal, `defaults.minConfidence: 0` so a served low-confidence observation is recorded
|
|
66
|
+
rather than silently replaced, and 0–3 score levels with an explicit `uncertain → review` band in
|
|
67
|
+
the consumer. The vendor's weighted overall grade and relative 100-point impact scale are
|
|
68
|
+
**rejected** — this method publishes per-category pass ratios with their coverage denominators and
|
|
69
|
+
no blended SEO/GEO grade.
|
|
70
|
+
2. **Rule identities** (`plugins/kk/scripts/seo-rules.ts` `VENDOR_RULES`) retain the 52 upstream
|
|
71
|
+
rule ids for traceability, each carrying `disposition` (`native|adapted|informational|deferred`),
|
|
72
|
+
KK-chosen `severity`, an `effort` band 1–4, a `heuristic` flag and the primary source with the date
|
|
73
|
+
it was checked. Neither severity nor effort is the vendor's.
|
|
74
|
+
3. **Source registry**: rule rows cite the primary source itself — RFC 9309 for robots matching,
|
|
75
|
+
Google Search Central (canonicalization, robots meta, sitemaps, AI optimization, common crawlers),
|
|
76
|
+
OpenAI's crawler documentation, web.dev Web Vitals. The dated registry, the per-source limits and
|
|
77
|
+
the refresh procedure are `plugins/kk/skills/smart-seo/references/seo-geo-sources.md`; the rubric,
|
|
78
|
+
scoring and action-priority interpretation is
|
|
79
|
+
`plugins/kk/skills/smart-seo/references/method.md`; the strict report-narrative contract is
|
|
80
|
+
`plugins/kk/skills/smart-seo/references/narrative.md`.
|
|
81
|
+
4. **Narrative rendering** uses KK-owned fixed templates over the audit artifact. Agents select and
|
|
82
|
+
order recorded references and cannot introduce prose, measurements, diagnoses or predictions.
|
|
83
|
+
5. **Vendor code, Python paths, browser/rendering stacks and bundled font assets are not shipped**;
|
|
84
|
+
the audit is native Bun/TypeScript over the existing stage runner (ADR-018) and `vendors/` stays
|
|
85
|
+
excluded from runtime and install resolution (ADR-036).
|
|
@@ -467,6 +467,38 @@ export function dailyCoverNormalize(args: string[]): void {
|
|
|
467
467
|
* no-content with the measured vs estimated minutes recorded. Over-max still fails loud — trimming
|
|
468
468
|
* is a different problem.
|
|
469
469
|
*/
|
|
470
|
+
/**
|
|
471
|
+
* Advisory speaker-consistency audit of a finished episode.
|
|
472
|
+
*
|
|
473
|
+
* Exists because an unanchored voice profile (voxcpm's `instruct` mode pins no speaker) shipped 59
|
|
474
|
+
* different speakers in the 20261015 episode and nothing but a human listening caught it. This runs
|
|
475
|
+
* the plugin's F0 audit and reports; it NEVER fails the run — a regression, a missing venv or a
|
|
476
|
+
* broken script must not stop publishing. A non-zero audit exit prints one WARNING line instead.
|
|
477
|
+
*/
|
|
478
|
+
export function dailyVoiceAudit(args: string[]): void {
|
|
479
|
+
const [workDir = '', runDate = '', pluginsPath = ''] = args;
|
|
480
|
+
if (!workDir) fail('missing work_dir');
|
|
481
|
+
if (!runDate) fail('missing run_date');
|
|
482
|
+
const contentPath = join(workDir, '30-audio', `${runDate}_11_generate_content.json`);
|
|
483
|
+
if (!isFile(contentPath)) {
|
|
484
|
+
console.log(`voice-audit: no episode content at ${contentPath}; skipping`);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const plugin = join(pluginsPath || 'plugins', 'generations', 'voxcpm-tts');
|
|
488
|
+
const python = join(plugin, '.venv', 'bin', 'python');
|
|
489
|
+
const script = join(plugin, 'scripts', 'audit-speaker-consistency.py');
|
|
490
|
+
if (!isFile(python) || !isFile(script)) {
|
|
491
|
+
console.log(`voice-audit: skipping (needs ${python} and ${script})`);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const audit = spawnSync(python, [script, contentPath], { encoding: 'utf-8' });
|
|
495
|
+
const out = `${audit.stdout ?? ''}${audit.stderr ?? ''}`.trim();
|
|
496
|
+
if (out) console.log(out);
|
|
497
|
+
if (audit.status !== 0) {
|
|
498
|
+
console.log('voice-audit: WARNING — the speaker-consistency audit flagged this episode (advisory)');
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
470
502
|
export function dailyEpisodeDuration(args: string[]): void {
|
|
471
503
|
const [workDir = '', runDate = '', minArg = '', maxArg = '', vdriver = ''] = args;
|
|
472
504
|
if (!workDir) fail('missing work_dir');
|
|
@@ -1989,9 +2021,17 @@ function voicescriptToBlockYaml(script: Record<string, unknown>): string {
|
|
|
1989
2021
|
return lines.join('\n');
|
|
1990
2022
|
}
|
|
1991
2023
|
|
|
1992
|
-
/** Measured driver rates from dailyGenerate. Unknown drivers
|
|
2024
|
+
/** Measured driver rates from dailyGenerate. Unknown drivers reuse the voicebox rate. */
|
|
1993
2025
|
function spokenCharRate(vdriver: string): number {
|
|
1994
|
-
|
|
2026
|
+
// Recalibrated 2026-10-15: episode measured 7,395 spoken chars / 1,490.9 s across 12 sections
|
|
2027
|
+
// (4.96 字/秒) — the effective gemini rate dropped ~8% below the 5.33-5.62 band calibrated
|
|
2028
|
+
// 2026-10-04/07, which consumed the fit's 2-min margin and tripped the 25-min gate at 25.2 min.
|
|
2029
|
+
if (vdriver === 'gemini') return 4.95;
|
|
2030
|
+
// voxcpm measured the same day on a 12-section zh+en episode: 6,772 chars / 1,297.7 s speech
|
|
2031
|
+
// (5.19 字/秒). The provisional 5.6 borrowed from voicebox let the fit budget reach 7,683 chars
|
|
2032
|
+
// — 24.6 min of audio, 18 s inside the 25-min gate. 5.2 puts a full-budget script at ~22.9 min.
|
|
2033
|
+
if (vdriver === 'voxcpm') return 5.2;
|
|
2034
|
+
return 5.6;
|
|
1995
2035
|
}
|
|
1996
2036
|
|
|
1997
2037
|
/**
|
|
@@ -232,69 +232,9 @@ export function itcReport(args: string[]): void {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
// ---------------------------------------------------------------------------
|
|
235
|
-
// 0150: publish-tail seams —
|
|
235
|
+
// 0150 / 0298: publish-tail seams — itc-materialize, itc-publish-plan
|
|
236
236
|
// ---------------------------------------------------------------------------
|
|
237
237
|
|
|
238
|
-
/** One row of the docs/design/kk-itc-end-to-end.md §5 target profile table. */
|
|
239
|
-
export interface TargetProfile {
|
|
240
|
-
transport: 'fanout' | 'browser';
|
|
241
|
-
/** `source` = the draft's own source_locale; anything else is fixed. */
|
|
242
|
-
locale: 'en' | 'zh' | 'ja' | 'source';
|
|
243
|
-
format: string;
|
|
244
|
-
cover: boolean;
|
|
245
|
-
/**
|
|
246
|
-
* V3 draft/live switch itc-publish-fanout writes into the variant Content metadata at send
|
|
247
|
-
* time. Returning null means the target has no switch for this run's mode and is rejected by
|
|
248
|
-
* name: x-pub's `operation: post` has no draft mode; wechatmp-pub refuses every live operation.
|
|
249
|
-
*/
|
|
250
|
-
switch: (live: boolean) => Record<string, unknown> | null;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Draft/live key per row, verified against each plugin's src/ (0150 R3):
|
|
254
|
-
// medium-pub metadata.publishStatus 'draft'|'public' (plugins/publishings/medium-pub/src/index.ts:49)
|
|
255
|
-
// emdash-pub metadata.published (plugins/publishings/emdash-pub/src/index.ts:254)
|
|
256
|
-
// surfdash-pub metadata.published (plugins/publishings/surfdash-pub/src/index.ts:93)
|
|
257
|
-
// zenn-pub metadata.published — defaults to LIVE when absent, so never omit (plugins/publishings/zenn-pub/src/index.ts:92)
|
|
258
|
-
// qiita-pub metadata.published, private is its inverse (plugins/publishings/qiita-pub/src/index.ts:70)
|
|
259
|
-
// wechatmp-pub metadata.operation, draft default; live refused (plugins/publishings/wechatmp-pub/src/index.ts:162,171)
|
|
260
|
-
// x-pub metadata.operation 'post' — no draft mode exists (plugins/publishings/x-pub/src/index.ts:64)
|
|
261
|
-
// substack/juejin/infoq/xhs always return a draft Result (plugins/publishings/substack-pub/src/index.ts:26);
|
|
262
|
-
// their live path is 0151's `kk:publish --live` agent flag, so the switch is documentation-only.
|
|
263
|
-
const publishedSwitch = (live: boolean) => ({ published: live });
|
|
264
|
-
const browserSwitch = (live: boolean): Record<string, unknown> => (live ? {} : { publishStatus: 'draft' });
|
|
265
|
-
|
|
266
|
-
export const TARGET_PROFILES: Record<string, TargetProfile> = {
|
|
267
|
-
'medium-pub': {
|
|
268
|
-
transport: 'fanout',
|
|
269
|
-
locale: 'en',
|
|
270
|
-
format: 'article',
|
|
271
|
-
cover: false,
|
|
272
|
-
switch: (live) => ({ publishStatus: live ? 'public' : 'draft' }),
|
|
273
|
-
},
|
|
274
|
-
'substack-pub': { transport: 'browser', locale: 'en', format: 'article', cover: false, switch: browserSwitch },
|
|
275
|
-
'emdash-pub': { transport: 'fanout', locale: 'source', format: 'article', cover: false, switch: publishedSwitch },
|
|
276
|
-
'surfdash-pub': { transport: 'fanout', locale: 'source', format: 'article', cover: false, switch: publishedSwitch },
|
|
277
|
-
'zenn-pub': { transport: 'fanout', locale: 'ja', format: 'article', cover: false, switch: publishedSwitch },
|
|
278
|
-
'qiita-pub': { transport: 'fanout', locale: 'ja', format: 'article', cover: false, switch: publishedSwitch },
|
|
279
|
-
'wechatmp-pub': {
|
|
280
|
-
transport: 'fanout',
|
|
281
|
-
locale: 'zh',
|
|
282
|
-
format: 'wechat-article',
|
|
283
|
-
cover: true,
|
|
284
|
-
switch: (live) => (live ? null : { operation: 'draft' }),
|
|
285
|
-
},
|
|
286
|
-
'juejin-pub': { transport: 'browser', locale: 'zh', format: 'article', cover: false, switch: browserSwitch },
|
|
287
|
-
'infoq-pub': { transport: 'browser', locale: 'zh', format: 'article', cover: false, switch: browserSwitch },
|
|
288
|
-
'xhs-pub': { transport: 'browser', locale: 'zh', format: 'short-note', cover: true, switch: browserSwitch },
|
|
289
|
-
'x-pub': {
|
|
290
|
-
transport: 'fanout',
|
|
291
|
-
locale: 'en',
|
|
292
|
-
format: 'short-post',
|
|
293
|
-
cover: false,
|
|
294
|
-
switch: (live) => (live ? { operation: 'post' } : null),
|
|
295
|
-
},
|
|
296
|
-
};
|
|
297
|
-
|
|
298
238
|
const DRAFT_FILE = '3-draft-draft-article.md';
|
|
299
239
|
|
|
300
240
|
/** First `cover.*` in 4-illustrations as a workspace-relative path, or undefined. */
|
|
@@ -383,65 +323,32 @@ export interface PublishPlan {
|
|
|
383
323
|
}
|
|
384
324
|
|
|
385
325
|
export function itcPublishPlan(args: string[]): void {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
fail('usage: itc-publish-plan <work_dir> <targets> <source_locale> <publish_live>');
|
|
326
|
+
if (process.env._KK_ITC_STAGE_NATIVE === '1') {
|
|
327
|
+
return;
|
|
389
328
|
}
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
if (profile.cover && !hasCover) {
|
|
415
|
-
fail(`target ${target} needs a cover image at 4-illustrations/cover.* in ${workDir}`);
|
|
416
|
-
}
|
|
417
|
-
const variant = `${profile.locale === 'source' ? sourceLocale : profile.locale}-${profile.format}`;
|
|
418
|
-
const sharesSourceArticle = variant === `${sourceLocale}-article`;
|
|
419
|
-
const entry = variants[variant] ?? {
|
|
420
|
-
file: sharesSourceArticle ? 'content.json' : `content.${variant}.json`,
|
|
421
|
-
adapt: !sharesSourceArticle,
|
|
422
|
-
limits: sharesSourceArticle ? undefined : {},
|
|
423
|
-
switches: {} as Record<string, unknown>,
|
|
424
|
-
};
|
|
425
|
-
Object.assign(entry.switches, switchValue);
|
|
426
|
-
variants[variant] = entry;
|
|
427
|
-
if (profile.transport === 'browser') browser.push({ target, variant });
|
|
428
|
-
else {
|
|
429
|
-
const group = fanout.get(variant);
|
|
430
|
-
if (group) group.push(target);
|
|
431
|
-
else fanout.set(variant, [target]);
|
|
432
|
-
}
|
|
329
|
+
const cliEntry = join(__dirname, '../../../apps/cli/src/index.ts');
|
|
330
|
+
let res: ReturnType<typeof spawnSync>;
|
|
331
|
+
if (existsSync(cliEntry)) {
|
|
332
|
+
res = spawnSync(process.execPath, [cliEntry, 'stage', 'run', 'itc-publish-plan', ...args], {
|
|
333
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
334
|
+
env: { ...process.env, _KK_ITC_STAGE_NATIVE: '1' },
|
|
335
|
+
});
|
|
336
|
+
} else {
|
|
337
|
+
res = spawnSync('kk', ['stage', 'run', 'itc-publish-plan', ...args], {
|
|
338
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
339
|
+
env: { ...process.env, _KK_ITC_STAGE_NATIVE: '1' },
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
if (res.stdout && res.stdout.length > 0) {
|
|
343
|
+
process.stdout.write(res.stdout);
|
|
344
|
+
}
|
|
345
|
+
if (res.stderr && res.stderr.length > 0) {
|
|
346
|
+
const errText = res.stderr.toString('utf-8');
|
|
347
|
+
console.error(errText.endsWith('\n') ? errText.slice(0, -1) : errText);
|
|
348
|
+
}
|
|
349
|
+
if (res.error || (res.status !== null && res.status !== 0)) {
|
|
350
|
+
process.exit(res.status ?? 1);
|
|
433
351
|
}
|
|
434
|
-
const plan: PublishPlan = {
|
|
435
|
-
live,
|
|
436
|
-
sourceLocale,
|
|
437
|
-
variants,
|
|
438
|
-
// canonical group order: the plan file must not depend on target argument order
|
|
439
|
-
fanout: [...fanout]
|
|
440
|
-
.sort(([a], [b]) => (a < b ? -1 : 1))
|
|
441
|
-
.map(([variant, groupTargets]) => ({ variant, targets: groupTargets })),
|
|
442
|
-
browser,
|
|
443
|
-
};
|
|
444
|
-
writeJson(join(workDir, '4-publish', 'publish-plan.json'), plan);
|
|
445
352
|
}
|
|
446
353
|
|
|
447
354
|
/** R3 — the adapt state's follow-up check: every adapt:true variant file exists with title/body. */
|
|
@@ -128,6 +128,21 @@ async function loadItcStages(): Promise<typeof import('./itc-stages.ts')> {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Load the seo-* helper sibling lazily (task 0281): this runner is resolved — and copied
|
|
133
|
+
* alone — from installs where the sibling may be absent, so the seo-* stages fail loud with a
|
|
134
|
+
* remediation path instead of breaking every stage at load.
|
|
135
|
+
*/
|
|
136
|
+
async function loadSeoStages(): Promise<typeof import('./seo-stages.ts')> {
|
|
137
|
+
try {
|
|
138
|
+
return await import('./seo-stages.ts');
|
|
139
|
+
} catch {
|
|
140
|
+
return fail(
|
|
141
|
+
'seo-stages.ts not found next to kk-workflow-stages.ts — install or refresh the kk package (bun link in a checkout)',
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
131
146
|
/** coreutils-style reason for the errno codes the staged file operations can hit. */
|
|
132
147
|
|
|
133
148
|
/**
|
|
@@ -1639,6 +1654,11 @@ if (import.meta.main)
|
|
|
1639
1654
|
dailyIntro(rest);
|
|
1640
1655
|
break;
|
|
1641
1656
|
}
|
|
1657
|
+
case 'daily-voice-audit': {
|
|
1658
|
+
const { dailyVoiceAudit } = await loadDailyStages();
|
|
1659
|
+
dailyVoiceAudit(rest);
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1642
1662
|
case 'daily-episode-duration': {
|
|
1643
1663
|
const { dailyEpisodeDuration } = await loadDailyStages();
|
|
1644
1664
|
dailyEpisodeDuration(rest);
|
|
@@ -1739,8 +1759,25 @@ if (import.meta.main)
|
|
|
1739
1759
|
itcAdaptVerify(rest);
|
|
1740
1760
|
break;
|
|
1741
1761
|
}
|
|
1762
|
+
case 'seo-preflight':
|
|
1763
|
+
case 'seo-collect':
|
|
1764
|
+
case 'seo-check':
|
|
1765
|
+
case 'seo-enrich':
|
|
1766
|
+
case 'seo-judge':
|
|
1767
|
+
case 'seo-score':
|
|
1768
|
+
case 'seo-report': {
|
|
1769
|
+
// The seo helper owns its dispatch: cancellation installation, the cancellation marker
|
|
1770
|
+
// and the conventional signal exit status must apply however the stage was reached.
|
|
1771
|
+
const { runSeoStage } = await loadSeoStages();
|
|
1772
|
+
try {
|
|
1773
|
+
await runSeoStage(stage, rest);
|
|
1774
|
+
} catch (err: unknown) {
|
|
1775
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
1776
|
+
}
|
|
1777
|
+
break;
|
|
1778
|
+
}
|
|
1742
1779
|
default:
|
|
1743
1780
|
fail(
|
|
1744
|
-
`unknown stage: ${stage ?? '(none)'} (expected prepare-itc|prepare-solo|prepare-storm|validate|wrap|duration|render-storm|itc-*|daily-*)`,
|
|
1781
|
+
`unknown stage: ${stage ?? '(none)'} (expected prepare-itc|prepare-solo|prepare-storm|validate|wrap|duration|render-storm|itc-*|daily-*|seo-*)`,
|
|
1745
1782
|
);
|
|
1746
1783
|
}
|