@gobing-ai/knowledge-kit 0.1.8 → 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 +725 -1101
- package/dist/board/daily-voice/index.js +722 -101
- package/dist/board/itc/index.js +13 -0
- package/dist/index.js +1792 -102
- 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/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 +580 -78
- 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 +75 -6
- 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/package.json
CHANGED
|
@@ -12328,8 +12328,10 @@ var InputConfigSchema = object({
|
|
|
12328
12328
|
config: string2().trim().min(1).optional(),
|
|
12329
12329
|
hours: number2().int().min(1).optional(),
|
|
12330
12330
|
languages: array(string2().trim().min(1)).optional(),
|
|
12331
|
-
horizon_dir: string2().trim().min(1).optional()
|
|
12331
|
+
horizon_dir: string2().trim().min(1).optional(),
|
|
12332
|
+
stale_fallback_ms: number2().int().min(0).optional()
|
|
12332
12333
|
});
|
|
12334
|
+
var DEFAULT_STALE_FALLBACK_MS = 26 * 3600000;
|
|
12333
12335
|
var defaultRunner = async (config, horizonDir) => {
|
|
12334
12336
|
const argv = [process.env.HORIZON_UV ?? "uv", "run", "horizon"];
|
|
12335
12337
|
if (config.hours !== undefined)
|
|
@@ -12447,6 +12449,27 @@ async function processIngestionIO(options, config, runner = defaultRunner, now =
|
|
|
12447
12449
|
continue;
|
|
12448
12450
|
docs.push(...digestToDocs(await fs.readFile(file), match[1], match[2]));
|
|
12449
12451
|
}
|
|
12452
|
+
if (docs.length === 0) {
|
|
12453
|
+
const fallbackMs = config.stale_fallback_ms ?? DEFAULT_STALE_FALLBACK_MS;
|
|
12454
|
+
let newest = null;
|
|
12455
|
+
for (const entry of entries) {
|
|
12456
|
+
const match = entry.match(digestRe);
|
|
12457
|
+
if (!match?.[1] || !match?.[2] || !langs.has(match[2]))
|
|
12458
|
+
continue;
|
|
12459
|
+
const stat = await fs.stat(join(summariesDir, entry));
|
|
12460
|
+
if (!stat)
|
|
12461
|
+
continue;
|
|
12462
|
+
if (!newest || stat.mtimeMs > newest.mtimeMs)
|
|
12463
|
+
newest = { entry, mtimeMs: stat.mtimeMs };
|
|
12464
|
+
}
|
|
12465
|
+
if (newest && runStartedAt - newest.mtimeMs <= fallbackMs) {
|
|
12466
|
+
const match = newest.entry.match(digestRe);
|
|
12467
|
+
if (match?.[1] && match?.[2]) {
|
|
12468
|
+
echoError(`horizon-ingest: no fresh digest this run \u2014 falling back to ${newest.entry} (${Math.round((runStartedAt - newest.mtimeMs) / 3600000)}h old)`);
|
|
12469
|
+
docs.push(...digestToDocs(await fs.readFile(join(summariesDir, newest.entry)), match[1], match[2]));
|
|
12470
|
+
}
|
|
12471
|
+
}
|
|
12472
|
+
}
|
|
12450
12473
|
if (docs.length === 0) {
|
|
12451
12474
|
echoError(`horizon-ingest: no fresh digest in ${summariesDir} (languages: ${[...langs].join(", ")}) \u2014 emitting []`);
|
|
12452
12475
|
}
|
|
@@ -19,8 +19,18 @@ const InputConfigSchema = z.object({
|
|
|
19
19
|
hours: z.number().int().min(1).optional(),
|
|
20
20
|
languages: z.array(z.string().trim().min(1)).optional(),
|
|
21
21
|
horizon_dir: z.string().trim().min(1).optional(),
|
|
22
|
+
/**
|
|
23
|
+
* When this tick's run writes no digest (Horizon exits 0 on an empty 6h
|
|
24
|
+
* window), fall back to the newest digest at most this many ms old instead
|
|
25
|
+
* of emitting []. Doc ids are date-keyed and stable, so repeats dedupe
|
|
26
|
+
* downstream (2026-10-23: Oct 21 contributed zero docs — every tick hit an
|
|
27
|
+
* empty window).
|
|
28
|
+
*/
|
|
29
|
+
stale_fallback_ms: z.number().int().min(0).optional(),
|
|
22
30
|
});
|
|
23
31
|
|
|
32
|
+
const DEFAULT_STALE_FALLBACK_MS = 26 * 3_600_000;
|
|
33
|
+
|
|
24
34
|
export interface HorizonRunResult {
|
|
25
35
|
exitCode: number;
|
|
26
36
|
stderr: string;
|
|
@@ -166,6 +176,30 @@ export async function processIngestionIO(
|
|
|
166
176
|
if (!stat || stat.mtimeMs < runStartedAt - 1000) continue; // stale file from an earlier run
|
|
167
177
|
docs.push(...digestToDocs(await fs.readFile(file), match[1], match[2]));
|
|
168
178
|
}
|
|
179
|
+
if (docs.length === 0) {
|
|
180
|
+
// This tick wrote no digest (empty fetch window exits 0). Reuse the newest
|
|
181
|
+
// digest while it is young enough to still matter for a daily podcast.
|
|
182
|
+
const fallbackMs = config.stale_fallback_ms ?? DEFAULT_STALE_FALLBACK_MS;
|
|
183
|
+
let newest: { entry: string; mtimeMs: number } | null = null;
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
const match = entry.match(digestRe);
|
|
186
|
+
if (!match?.[1] || !match?.[2] || !langs.has(match[2])) continue;
|
|
187
|
+
const stat = await fs.stat(join(summariesDir, entry));
|
|
188
|
+
if (!stat) continue;
|
|
189
|
+
if (!newest || stat.mtimeMs > newest.mtimeMs) newest = { entry, mtimeMs: stat.mtimeMs };
|
|
190
|
+
}
|
|
191
|
+
if (newest && runStartedAt - newest.mtimeMs <= fallbackMs) {
|
|
192
|
+
const match = newest.entry.match(digestRe);
|
|
193
|
+
if (match?.[1] && match?.[2]) {
|
|
194
|
+
echoError(
|
|
195
|
+
`horizon-ingest: no fresh digest this run — falling back to ${newest.entry} (${Math.round(
|
|
196
|
+
(runStartedAt - newest.mtimeMs) / 3_600_000,
|
|
197
|
+
)}h old)`,
|
|
198
|
+
);
|
|
199
|
+
docs.push(...digestToDocs(await fs.readFile(join(summariesDir, newest.entry)), match[1], match[2]));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
169
203
|
if (docs.length === 0) {
|
|
170
204
|
echoError(
|
|
171
205
|
`horizon-ingest: no fresh digest in ${summariesDir} (languages: ${[...langs].join(', ')}) — emitting []`,
|
|
@@ -9,6 +9,14 @@ defaults:
|
|
|
9
9
|
maxResults: 8
|
|
10
10
|
fixture: false
|
|
11
11
|
|
|
12
|
+
# Per-workflow settings. `publish_preset` names the publish preset that owns the daily channel
|
|
13
|
+
# matrix (files live in `plugins/kk/publish-presets/`, overridable per project under
|
|
14
|
+
# `.kk/publish-presets/`). The preset decides WHICH channels publish; `live` is never in a preset
|
|
15
|
+
# file — it is a launch var (`live_channels`) or an installed schedule entry (ADR-022).
|
|
16
|
+
workflows:
|
|
17
|
+
kk-daily-ai-voice3:
|
|
18
|
+
publish_preset: "daily-ai-voice"
|
|
19
|
+
|
|
12
20
|
# Plugin credentials — paste values between the quotes.
|
|
13
21
|
# Path: plugins/<collection>/<name>/env — each entry is injected into that plugin's
|
|
14
22
|
# process environment at exec time. A real environment variable always wins
|
package/plugins/kk/plugin.json
CHANGED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "daily-ai-voice",
|
|
4
|
+
"targets": [
|
|
5
|
+
{
|
|
6
|
+
"plugin": "surfdash-pub",
|
|
7
|
+
"operation": "post",
|
|
8
|
+
"variant": "article",
|
|
9
|
+
"tier": 0,
|
|
10
|
+
"window": "after-generate",
|
|
11
|
+
"mode": "draft",
|
|
12
|
+
"required": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"plugin": "podcast-pub",
|
|
16
|
+
"operation": "episode",
|
|
17
|
+
"variant": "episode",
|
|
18
|
+
"tier": 0,
|
|
19
|
+
"window": "after-generate",
|
|
20
|
+
"mode": "draft",
|
|
21
|
+
"required": true
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"plugin": "wechatmp-pub",
|
|
25
|
+
"operation": "播客",
|
|
26
|
+
"variant": "episode",
|
|
27
|
+
"tier": 1,
|
|
28
|
+
"window": "after-generate",
|
|
29
|
+
"mode": "draft"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"plugin": "xhs-pub",
|
|
33
|
+
"operation": "发播客",
|
|
34
|
+
"variant": "episode",
|
|
35
|
+
"tier": 1,
|
|
36
|
+
"window": "after-generate",
|
|
37
|
+
"mode": "draft"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"plugin": "wechatmp-pub",
|
|
41
|
+
"operation": "文章",
|
|
42
|
+
"variant": "article",
|
|
43
|
+
"tier": 2,
|
|
44
|
+
"window": "after-generate",
|
|
45
|
+
"mode": "draft",
|
|
46
|
+
"options": {
|
|
47
|
+
"collection": "每日AI资讯"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"plugin": "xhs-pub",
|
|
52
|
+
"operation": "写长文",
|
|
53
|
+
"variant": "article",
|
|
54
|
+
"tier": 2,
|
|
55
|
+
"window": "after-generate",
|
|
56
|
+
"mode": "dummy"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"plugin": "xhs-pub",
|
|
60
|
+
"operation": "上传图文",
|
|
61
|
+
"variant": "cards",
|
|
62
|
+
"tier": 3,
|
|
63
|
+
"window": "after-generate",
|
|
64
|
+
"mode": "off"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"plugin": "weibo-pub",
|
|
68
|
+
"operation": "article",
|
|
69
|
+
"variant": "article",
|
|
70
|
+
"tier": 2,
|
|
71
|
+
"window": "cn-peak",
|
|
72
|
+
"mode": "draft"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"plugin": "x-pub",
|
|
76
|
+
"operation": "article",
|
|
77
|
+
"variant": "article",
|
|
78
|
+
"tier": 2,
|
|
79
|
+
"window": "cn-peak",
|
|
80
|
+
"mode": "draft"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"plugin": "x-pub",
|
|
84
|
+
"operation": "post",
|
|
85
|
+
"variant": "social:x",
|
|
86
|
+
"tier": 3,
|
|
87
|
+
"window": "overseas-rss",
|
|
88
|
+
"mode": "draft"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"plugin": "weibo-pub",
|
|
92
|
+
"operation": "post",
|
|
93
|
+
"variant": "social:weibo",
|
|
94
|
+
"tier": 3,
|
|
95
|
+
"window": "overseas-rss",
|
|
96
|
+
"mode": "draft"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"plugin": "threads-pub",
|
|
100
|
+
"operation": "post",
|
|
101
|
+
"variant": "social:threads",
|
|
102
|
+
"tier": 3,
|
|
103
|
+
"window": "overseas-rss",
|
|
104
|
+
"mode": "draft"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"plugin": "shipinhao-pub",
|
|
108
|
+
"operation": "图文",
|
|
109
|
+
"variant": "cards",
|
|
110
|
+
"tier": 3,
|
|
111
|
+
"window": "overseas-rss",
|
|
112
|
+
"mode": "off"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"plugin": "threads-pub",
|
|
116
|
+
"operation": "post-images",
|
|
117
|
+
"variant": "cards",
|
|
118
|
+
"tier": 3,
|
|
119
|
+
"window": "overseas-rss",
|
|
120
|
+
"mode": "off"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# kk-daily-publish3-cn-peak — domestic live window (task 0323 R5).
|
|
2
|
+
#
|
|
3
|
+
# Fires at 17:00 local because the audience window is 09:00 Asia/Shanghai and launchd/cron
|
|
4
|
+
# intervals follow the MACHINE's zone; the first node (`publish-matrix-wait-until 09:00
|
|
5
|
+
# Asia/Shanghai`) sleeps the remainder, which is 1 h from 17:00 PDT and 0 h after the DST flip —
|
|
6
|
+
# so the entry never needs editing twice a year.
|
|
7
|
+
#
|
|
8
|
+
# `live_channels` is baked in: this installed line IS the operator's ADR-022 consent for a live
|
|
9
|
+
# send. Nothing in the workflow or the preset can produce `live` on its own.
|
|
10
|
+
#
|
|
11
|
+
# Rendered by `kk schedule render kk-daily-publish3-cn-peak --platform cron --repo <checkout>`;
|
|
12
|
+
# kk never edits the operator's crontab. MERGE, never replace:
|
|
13
|
+
#
|
|
14
|
+
# crontab -l > /tmp/kk-cn-peak.cron 2>/dev/null || :
|
|
15
|
+
# kk schedule render kk-daily-publish3-cn-peak --platform cron --repo "$PWD" >> /tmp/kk-cn-peak.cron
|
|
16
|
+
# crontab /tmp/kk-cn-peak.cron
|
|
17
|
+
#
|
|
18
|
+
# `run_date` is computed at tick time in America/Los_Angeles: a run that starts at 17:00 PDT is
|
|
19
|
+
# still "today" for the day dir the 04:30 generation wrote.
|
|
20
|
+
0 17 * * * cd {{repo}} && mkdir -p .works/kk-daily-publish3 && PATH="{{home}}/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" TZ=America/Los_Angeles spur workflow run plugins/kk/workflows/kk-daily-publish3.yaml --vars "{\"work_dir\":\"{{repo}}/.works/kk-daily-publish3/$(TZ=America/Los_Angeles date +%Y%m%d)\",\"run_date\":\"$(TZ=America/Los_Angeles date +%F)\",\"window\":\"cn-peak\",\"live_channels\":\"wechatmp-pub,xhs-pub,weibo-pub,x-pub\"}" >> {{repo}}/.works/kk-daily-publish3/cn-peak.log 2>&1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# kk-daily-publish3-overseas — overseas window behind the podcast RSS gate (task 0323 R5).
|
|
2
|
+
#
|
|
3
|
+
# 07:00 America/Los_Angeles, which needs no DST adjustment: the entry is defined in the zone the
|
|
4
|
+
# machine already runs in. The gated date is the PREVIOUS day, because the observed episodes land
|
|
5
|
+
# 13:43–15:22 PDT (after this tick) — `run_date` is therefore yesterday's date, not today's.
|
|
6
|
+
#
|
|
7
|
+
# The gate decides whether anything publishes: a miss cancels the overseas targets and runs
|
|
8
|
+
# `diagnose` + the tier-0-only repair. This line carries no `live_channels`; the overseas channels
|
|
9
|
+
# in the shipped preset are `draft`, so a live overseas post stays an operator launch.
|
|
10
|
+
#
|
|
11
|
+
# Rendered by `kk schedule render kk-daily-publish3-overseas --platform cron --repo <checkout>`;
|
|
12
|
+
# kk never edits the operator's crontab. MERGE, never replace:
|
|
13
|
+
#
|
|
14
|
+
# crontab -l > /tmp/kk-overseas.cron 2>/dev/null || :
|
|
15
|
+
# kk schedule render kk-daily-publish3-overseas --platform cron --repo "$PWD" >> /tmp/kk-overseas.cron
|
|
16
|
+
# crontab /tmp/kk-overseas.cron
|
|
17
|
+
0 7 * * * cd {{repo}} && mkdir -p .works/kk-daily-publish3 && PATH="{{home}}/.bun/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" TZ=America/Los_Angeles spur workflow run plugins/kk/workflows/kk-daily-publish3.yaml --vars "{\"work_dir\":\"{{repo}}/.works/kk-daily-publish3/$(TZ=America/Los_Angeles date -v-1d +%Y%m%d 2>/dev/null || TZ=America/Los_Angeles date -d yesterday +%Y%m%d)\",\"run_date\":\"$(TZ=America/Los_Angeles date -v-1d +%F 2>/dev/null || TZ=America/Los_Angeles date -d yesterday +%F)\",\"window\":\"overseas-rss\"}" >> {{repo}}/.works/kk-daily-publish3/overseas.log 2>&1
|