@gobing-ai/knowledge-kit 0.0.25 → 0.0.26

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.
@@ -20,10 +20,12 @@ vars:
20
20
  limit: "10"
21
21
  language: "zh"
22
22
  voice_profile: "robin-news"
23
- # 20260917: voice driver switch — voicebox (default, voice-gen) | ominivoice (omni-voice-gen) | gemini (gemini-tts).
24
- # 20260920: default flipped to voicebox — operator A/B at matched speech rate (~5.2 chars/s)
25
- # judged voicebox clearly better (ominivoice carries ~1min dead air over 16min + ASR-garble class).
26
- vdriver: "voicebox"
23
+ # Voice driver switch — voicebox (voice-gen) | ominivoice (omni-voice-gen) | gemini (gemini-tts).
24
+ # 20260917 introduced the switch; 20260920 flipped default to voicebox after an operator A/B;
25
+ # 20260929 operator override: gemini-tts is the default again (verified live on this machine —
26
+ # robin-news replicated profile, GEMINI_API_KEY + GEMINI_TTS_MODEL via ~/.config/kk/config.yaml
27
+ # env block; smoke render 6.8s). Flip back with vdriver="voicebox".
28
+ vdriver: "gemini"
27
29
  # 20260917 review #7: 8s intro sting prepended to every daily output; empty = skip.
28
30
  intro_music: ".works/kk-daily-ai-voice/AI每日资讯_8秒播客片头.mp3"
29
31
  # 20260917 review #4/#6: surfdash checkout the patch stage commits to.
@@ -50,21 +52,30 @@ vars:
50
52
  # default keeps F614's pinned look the default; availability trades against it only on opt-in.
51
53
  cover_fallback: ""
52
54
  # E8: XHS image-card target. Cards are planned from the lead plan item (the same source the
53
- # cover uses) and rendered through the pinned xhs-card/xhs-knowledge presets. `xhs_live` stays a
54
- # separate launch-time switch (ADR-022), so an unattended run drafts and never posts live.
55
- # Default OFF (2026-09-28): XHS warned the operator about automated login/publish activity.
56
- # `xhs-pub` always launches a headed browser and drives the creator console, and an unattended
57
- # daily job repeating that is precisely the pattern the platform flags — so the target is
58
- # operator-opt-in until a reviewed automation policy exists. Do NOT flip this on for a scheduled
59
- # run; publish XHS deliberately, by hand, and rarely.
60
- xhs_enabled: "false"
55
+ # cover uses) and rendered through the pinned xhs-card/xhs-knowledge presets, then the xhs-pub
56
+ # headed browser saves them into the creator draft box.
57
+ # 2026-09-28 default OFF: XHS had warned the operator about automated login/publish activity,
58
+ # because `xhs-pub` always launches a headed browser and drives the creator console.
59
+ # 2026-09-29 operator decision: default ON — daily runs fill the draft box (best-practice
60
+ # default). The safety rail is `xhs_live: "false"` below: an unattended run drafts and never
61
+ # posts live. To post live, run ad-hoc with xhs_live="true" — deliberately, by hand.
62
+ xhs_enabled: "true"
61
63
  xhs_cards: "4"
62
64
  xhs_style: "xhs-knowledge"
63
65
  # Same credential surface as the cover pin: the provider/model must be one this machine can
64
66
  # actually reach, and each provider renders its own look.
65
67
  xhs_provider: "minimax"
66
68
  xhs_model: "image-01"
69
+ # ADR-022 rail: draft-box only. "true" posts live and stays a launch-time opt-in.
67
70
  xhs_live: "false"
71
+
72
+ # WeChat MP (公众号): the daily article is pasted into the MP console editor and saved to the
73
+ # draft box (草稿箱) through wechatmp-pub's persistent-profile browser transport. The plugin
74
+ # runs a headless session preflight first: a sessionless run refuses fast (ok:false) and the
75
+ # stage stays non-blocking. The rail mirrors xhs: an unattended run drafts and never posts
76
+ # live — 发表 only on an ad-hoc wechat_live="true" run, deliberately, by hand.
77
+ wechat_enabled: "true"
78
+ wechat_live: "false"
68
79
  plan_max_items: "20"
69
80
  plan_translate_enabled: "true"
70
81
  article_write_enabled: "true"
@@ -72,7 +83,7 @@ vars:
72
83
  # article/cover straight to script (template build, no plan file is written).
73
84
  script_write_enabled: "true"
74
85
  plugins_path: ""
75
- # Projected by the publish state from 3-publish/<run_date>_17_publish_publish-status.txt;
86
+ # Projected by the publish state from 31-publish/<run_date>_17_publish_publish-status.txt;
76
87
  # guards test this var instead of cat-ing the file (state at decision time).
77
88
  publish_status: ""
78
89
  last30days_topic: "AI news"
@@ -129,8 +140,8 @@ states:
129
140
  # 45m leash; aihot/last30days keep the default.
130
141
  command: >-
131
142
  __STAMP_T0="$(date -u +%FT%TZ)"; trap '[ -n "${vars.work_dir}" ] && printf "{\"step\":\"collect\",\"startedAt\":\"%s\",\"endedAt\":\"%s\"}\n" "$__STAMP_T0" "$(date -u +%FT%TZ)" >> "${vars.work_dir}/step-timing.json"' EXIT;
132
- if [ -f "${vars.work_dir}/1-ingest/${vars.run_date}_02_collect_blended.json" ]; then echo "collect cached: ${vars.work_dir}/1-ingest/${vars.run_date}_02_collect_blended.json"; exit 0; fi;
133
- kk executor fan-in --source "aihot-ingest:${vars.work_dir}/1-ingest/source.json" --source "last30days-ingest:${vars.work_dir}/1-ingest/last30days.json" --source "horizon-ingest:${vars.work_dir}/1-ingest/horizon.json" --source-timeout-override "horizon-ingest:2700000" --out "${vars.work_dir}/1-ingest/${vars.run_date}_02_collect_blended.json"
143
+ if [ -f "${vars.work_dir}/10-ingest/${vars.run_date}_02_collect_blended.json" ]; then echo "collect cached: ${vars.work_dir}/10-ingest/${vars.run_date}_02_collect_blended.json"; exit 0; fi;
144
+ kk executor fan-in --source "aihot-ingest:${vars.work_dir}/10-ingest/source.json" --source "last30days-ingest:${vars.work_dir}/10-ingest/last30days.json" --source "horizon-ingest:${vars.work_dir}/10-ingest/horizon.json" --source-timeout-override "horizon-ingest:2700000" --out "${vars.work_dir}/10-ingest/${vars.run_date}_02_collect_blended.json"
134
145
  - kind: shell
135
146
  options:
136
147
  command: >-
@@ -161,13 +172,13 @@ states:
161
172
  agent: ${vars.agent}
162
173
  # ADR-115 error tier: keep this prompt <= 1000 chars (0133 R3; 0138 R4a adds the copy discipline).
163
174
  input: |
164
- Read ${vars.work_dir}/2-plan/${vars.run_date}_04_quality-control-content_candidates.json — metadata.docs (Doc[]) is the plan; don't edit it.
175
+ Read ${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json — metadata.docs (Doc[]) is the plan; don't edit it.
165
176
  For items with needsTranslation, translate "title", "body", and "metadata.brief" (when present) into natural simplified Chinese.
166
177
  Titles read as a news event (subject + action + object) — e.g. "OpenAI 发布 Sora 应用,集成 Sora 2 模型". Keep product/model/company names verbatim, preserve body URLs, use 「」 not ASCII double quotes.
167
178
  Copy discipline: reader-facing news copy — no scaffold labels (「可做角度」「为什么现在值得注意」「社区讨论」「背景」「潜在影响」「影响」), no duplicated labels or hedging (「读者宜另行核实」「仍待验证」) — merge their substance into prose or drop.
168
179
  Keep other fields (id, sourceUri, mediaType, metadata), technical terms as-is; no trailing commas or comments.
169
- Output strictly valid JSON — a same-length, same-order array with the same ids — to ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json.
170
- expectFile: ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json
180
+ Output strictly valid JSON — a same-length, same-order array with the same ids — to ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json.
181
+ expectFile: ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json
171
182
  allowAppend: false
172
183
 
173
184
  - id: article-write
@@ -179,11 +190,11 @@ states:
179
190
  agent: ${vars.agent}
180
191
  # ADR-115 error tier: keep this prompt <= 1000 chars (0133 R3).
181
192
  input: |
182
- Read ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json — metadata.docs (Doc[]) is the translated plan; don't edit it.
193
+ Read ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json — metadata.docs (Doc[]) is the translated plan; don't edit it.
183
194
  Write a morning-news prose article in natural simplified Chinese: title line "# 每日 AI 资讯 — ${vars.run_date}", an intro paragraph (2–3 sentences), then one section per item (## numbered title, 2–4 sentences of flowing prose, source link [来源:<label>](<sourceUri>) inline), a closing paragraph tying items together.
184
195
  Narrative register — smooth transitions between items, no list-like bulleting, no scaffold labels (「可做角度」「背景」「潜在影响」), no hedging (「读者宜另行核实」「仍待验证」). Keep facts/URLs from the plan verbatim; product/model names as-is; 「」 quotes.
185
- Output the markdown to ${vars.work_dir}/2-article/${vars.run_date}_06_article-write_body.md.
186
- expectFile: ${vars.work_dir}/2-article/${vars.run_date}_06_article-write_body.md
196
+ Output the markdown to ${vars.work_dir}/22-article/${vars.run_date}_06_article-write_body.md.
197
+ expectFile: ${vars.work_dir}/22-article/${vars.run_date}_06_article-write_body.md
187
198
  allowAppend: false
188
199
 
189
200
  - id: article
@@ -206,12 +217,12 @@ states:
206
217
  agent: ${vars.agent}
207
218
  # ADR-115 error tier: keep this prompt <= 1000 chars.
208
219
  input: |
209
- Read ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json — a JSON array of news docs; don't edit it.
220
+ Read ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json — a JSON array of news docs; don't edit it.
210
221
  Take item 1 only (its "title" and "metadata.brief") — the episode's lead story.
211
222
  Write one concrete visual scene in English, ≤240 characters, that a viewer would connect to that story: objects, settings, symbols, metaphor.
212
223
  No text, letters, numbers, logos, brand marks, flags, or recognizable real people. No style, color, lighting, or composition words — the preset owns those.
213
- Output strictly valid JSON {"subject": "..."} to ${vars.work_dir}/2-cover/${vars.run_date}_07_cover-brief.json.
214
- expectFile: ${vars.work_dir}/2-cover/${vars.run_date}_07_cover-brief.json
224
+ Output strictly valid JSON {"subject": "..."} to ${vars.work_dir}/23-cover/${vars.run_date}_07_cover-brief.json.
225
+ expectFile: ${vars.work_dir}/23-cover/${vars.run_date}_07_cover-brief.json
215
226
  allowAppend: false
216
227
  - kind: shell
217
228
  options:
@@ -242,11 +253,11 @@ states:
242
253
  agent: ${vars.agent}
243
254
  # ADR-115 error tier: keep this prompt <= 1000 chars.
244
255
  input: |
245
- Read ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json — a JSON array of docs; use each doc's `id`; don't edit it. Also read the style contract ${vars.work_dir}/2-script/${vars.run_date}_08_script-write_style.md and obey its char caps and banned phrases.
256
+ Read ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json — a JSON array of docs; use each doc's `id`; don't edit it. Also read the style contract ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_style.md and obey its char caps and banned phrases.
246
257
  For each doc write a `lead` (a spoken bridge into the title, not containing it) and an `insight` (why it matters, grounded only in that doc's facts).
247
258
  Write an `intro` hooking today's actual themes and an `outro`; no greeting or sign-off — the builder adds both.
248
- Output only the JSON object {"version":1,"intro":"…","outro":"…","items":[{"id":"…","lead":"…","insight":"…"}]} with one item per doc id to ${vars.work_dir}/2-script/${vars.run_date}_08_script-write_plan.json.
249
- expectFile: ${vars.work_dir}/2-script/${vars.run_date}_08_script-write_plan.json
259
+ Output only the JSON object {"version":1,"intro":"…","outro":"…","items":[{"id":"…","lead":"…","insight":"…"}]} with one item per doc id to ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json.
260
+ expectFile: ${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json
250
261
  allowAppend: false
251
262
 
252
263
  - id: script
@@ -263,7 +274,7 @@ states:
263
274
  onEnter:
264
275
  - kind: hitl.confirm
265
276
  options:
266
- prompt: "Review daily AI news VoiceScript at ${vars.work_dir}/2-script/${vars.run_date}_08_script_voicescript.yaml. Proceed to voice generation?"
277
+ prompt: "Review daily AI news VoiceScript at ${vars.work_dir}/24-script/${vars.run_date}_08_script_voicescript.yaml. Proceed to voice generation?"
267
278
  var: __hitlAnswer
268
279
 
269
280
  - id: wrap-docs
@@ -342,13 +353,13 @@ states:
342
353
  agent: ${vars.agent}
343
354
  # ADR-115 error tier: keep this prompt <= 1000 chars.
344
355
  input: |
345
- Read ${vars.work_dir}/2-plan/${vars.run_date}_03_plan_plan.json — a JSON array of news docs; don't edit it.
356
+ Read ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json — a JSON array of news docs; don't edit it.
346
357
  Take item 1 only (its "title" and "metadata.brief") — the lead story.
347
358
  Write a Xiaohongshu note: "title" (≤20 chars) and "body" (Chinese note ≤1000 chars, ending with 3-5 hashtags).
348
359
  Write exactly ${vars.xhs_cards} cards: card 1 role "cover", the rest "content", except a final "closing". Each card carries "role", "copy" (Chinese on-card headline ≤12 chars), "points" (2-4 short Chinese bullets), "layout", "subject" (one concrete English visual scene), "sourcePoint" (the lead-story fact that card uses).
349
360
  Ground every "copy", "points" and "sourcePoint" in that story alone — no invented facts. No text, letters, numbers, logos or real people in "subject".
350
- Output strictly valid JSON {"title": "...", "body": "...", "cards": [...]} to ${vars.work_dir}/2-xhs/${vars.run_date}_18_xhs_plan.json.
351
- expectFile: ${vars.work_dir}/2-xhs/${vars.run_date}_18_xhs_plan.json
361
+ Output strictly valid JSON {"title": "...", "body": "...", "cards": [...]} to ${vars.work_dir}/25-xhs/${vars.run_date}_18_xhs_plan.json.
362
+ expectFile: ${vars.work_dir}/25-xhs/${vars.run_date}_18_xhs_plan.json
352
363
  allowAppend: false
353
364
  - kind: shell
354
365
  onError: continue
@@ -365,6 +376,15 @@ states:
365
376
  command: >-
366
377
  kk stage daily-publish-xhs "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.xhs_live}"
367
378
 
379
+ - id: wechat-publish
380
+ description: "Publish the daily article to the WeChat MP draft box via wechatmp-pub (console browser transport) — draft, or live only when wechat_live=true; independent and non-blocking: its outcome never enters publish_status; a sessionless profile refuses fast (headless preflight) and the run continues"
381
+ onEnter:
382
+ - kind: shell
383
+ onError: continue
384
+ options:
385
+ command: >-
386
+ kk stage daily-publish-wechat "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.wechat_live}"
387
+
368
388
  - id: publish
369
389
  description: "Classify the sequenced surfdash → podcast outcomes full|partial|none into publish-status.txt (exit 0 in all three — routing is transition-owned; task 0118: per-target classification over the merged result.json)"
370
390
  onEnter:
@@ -374,7 +394,7 @@ states:
374
394
  kk stage daily-publish-classify "${vars.work_dir}" "${vars.run_date}"
375
395
  - kind: file.read.into-var
376
396
  options:
377
- path: ${vars.work_dir}/3-publish/${vars.run_date}_17_publish_publish-status.txt
397
+ path: ${vars.work_dir}/31-publish/${vars.run_date}_17_publish_publish-status.txt
378
398
  var: publish_status
379
399
 
380
400
  - id: patch-surfdash
@@ -410,11 +430,11 @@ states:
410
430
  kk stage daily-translate-localize "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}"
411
431
  - kind: file.read.into-var
412
432
  options:
413
- path: ${vars.work_dir}/3-publish/${vars.run_date}_20_translate-localize_en-post-path.txt
433
+ path: ${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_en-post-path.txt
414
434
  var: surfdash_en_post_path
415
435
  - kind: file.read.into-var
416
436
  options:
417
- path: ${vars.work_dir}/3-publish/${vars.run_date}_20_translate-localize_ja-post-path.txt
437
+ path: ${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_ja-post-path.txt
418
438
  var: surfdash_ja_post_path
419
439
  - kind: agent.run
420
440
  options:
@@ -430,7 +450,7 @@ states:
430
450
  - kind: shell
431
451
  options:
432
452
  command: >-
433
- kk stage daily-translate-sync "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.work_dir}/3-publish/${vars.run_date}_20_translate-localize_zh-post-path.txt"
453
+ kk stage daily-translate-sync "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_zh-post-path.txt"
434
454
 
435
455
  - id: done
436
456
  description: "Terminal — Daily AI news pipeline completed (collect → QC'd plan → article/cover/script/voice → publish/locales)"
@@ -466,7 +486,7 @@ transitions:
466
486
  guard:
467
487
  kind: shell
468
488
  options:
469
- command: 'test "$(jq ''.metadata.docs | length == 0'' "${vars.work_dir}/2-plan/${vars.run_date}_04_quality-control-content_candidates.json")" = "true"'
489
+ command: 'test "$(jq ''.metadata.docs | length == 0'' "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json")" = "true"'
470
490
 
471
491
  - from: quality-control-content
472
492
  to: plan-translate
@@ -520,7 +540,7 @@ transitions:
520
540
  guard:
521
541
  kind: shell
522
542
  options:
523
- command: 'test "${vars.cover_enabled}" = "true" && test ! -f "${vars.work_dir}/2-cover/${vars.run_date}_07_cover_cover.png"'
543
+ command: 'test "${vars.cover_enabled}" = "true" && test ! -f "${vars.work_dir}/23-cover/${vars.run_date}_07_cover_cover.png"'
524
544
 
525
545
  # F613 R3: first match wins — the cover edge stays above script-write so the cover still
526
546
  # generates before the plan is authored; script-write sits above the always `-> script` edges
@@ -531,7 +551,7 @@ transitions:
531
551
  guard:
532
552
  kind: shell
533
553
  options:
534
- command: 'test "${vars.script_write_enabled}" = "true" && test "${vars.language}" = "zh" && test ! -f "${vars.work_dir}/2-script/${vars.run_date}_08_script-write_plan.json" && test ! -f "${vars.work_dir}/2-script/${vars.run_date}_08_script_voicescript.yaml"'
554
+ command: 'test "${vars.script_write_enabled}" = "true" && test "${vars.language}" = "zh" && test ! -f "${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json" && test ! -f "${vars.work_dir}/24-script/${vars.run_date}_08_script_voicescript.yaml"'
535
555
 
536
556
  - from: article
537
557
  to: script
@@ -545,7 +565,7 @@ transitions:
545
565
  guard:
546
566
  kind: shell
547
567
  options:
548
- command: 'test "${vars.script_write_enabled}" = "true" && test "${vars.language}" = "zh" && test ! -f "${vars.work_dir}/2-script/${vars.run_date}_08_script-write_plan.json" && test ! -f "${vars.work_dir}/2-script/${vars.run_date}_08_script_voicescript.yaml"'
568
+ command: 'test "${vars.script_write_enabled}" = "true" && test "${vars.language}" = "zh" && test ! -f "${vars.work_dir}/24-script/${vars.run_date}_08_script-write_plan.json" && test ! -f "${vars.work_dir}/24-script/${vars.run_date}_08_script_voicescript.yaml"'
549
569
 
550
570
  - from: cover
551
571
  to: script
@@ -670,6 +690,20 @@ transitions:
670
690
  guard:
671
691
  kind: always
672
692
 
693
+ - from: publish-podcast
694
+ to: wechat-publish
695
+ description: "wechat_enabled -> paste the daily article into the WeChat MP console and save it to the draft box; first-match-wins, so this sits above the classification edge (WeChat is independent and never gates publish_status)"
696
+ guard:
697
+ kind: shell
698
+ options:
699
+ command: 'test "${vars.wechat_enabled}" = "true"'
700
+
701
+ - from: wechat-publish
702
+ to: publish
703
+ description: "WeChat draft dispatched (or skipped: onError continue) -> classify the surfdash/podcast outcomes; WeChat contributes no target to the classification"
704
+ guard:
705
+ kind: always
706
+
673
707
  - from: publish-podcast
674
708
  to: publish
675
709
  description: "Podcast dispatched -> classify the per-target outcomes full|partial|none"