@gobing-ai/knowledge-kit 0.0.23 → 0.0.25

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.
Files changed (67) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +137 -59
  3. package/package.json +4 -4
  4. package/plugins/generations/content-gen/dist/index.js +97 -45
  5. package/plugins/generations/core-facts-gen/dist/index.js +106 -57
  6. package/plugins/generations/daily-article-gen/dist/index.js +105 -56
  7. package/plugins/generations/dailynews-gen/dist/index.js +235 -57
  8. package/plugins/generations/dailynews-gen/src/index.ts +67 -2
  9. package/plugins/generations/dailynews-gen/src/script-builder.ts +36 -15
  10. package/plugins/generations/dailynews-gen/src/script-plan.ts +142 -0
  11. package/plugins/generations/episode-plan-gen/dist/index.js +115 -66
  12. package/plugins/generations/gemini-tts/README.md +24 -0
  13. package/plugins/generations/gemini-tts/dist/index.js +326 -260
  14. package/plugins/generations/gemini-tts/src/gemini-client.ts +41 -11
  15. package/plugins/generations/image-gen/dist/index.js +338 -117
  16. package/plugins/generations/image-gen/presets/formats/daily-news-cover.yaml +19 -0
  17. package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +55 -0
  18. package/plugins/generations/image-gen/presets/styles/daily-news.yaml +9 -0
  19. package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +7 -0
  20. package/plugins/generations/image-gen/src/index.ts +148 -14
  21. package/plugins/generations/image-gen/src/job.ts +30 -0
  22. package/plugins/generations/image-gen/src/providers/errors.ts +91 -0
  23. package/plugins/generations/image-gen/src/providers/types.ts +79 -0
  24. package/plugins/generations/news-report-gen/dist/index.js +136 -55
  25. package/plugins/generations/news-report-gen/src/index.ts +57 -1
  26. package/plugins/generations/voice-gen/dist/index.js +119 -67
  27. package/plugins/ingestions/aihot-ingest/dist/index.js +103 -53
  28. package/plugins/ingestions/horizon-ingest/dist/index.js +102 -53
  29. package/plugins/ingestions/karakeep-local/dist/index.js +273 -224
  30. package/plugins/ingestions/last30days-ingest/dist/index.js +97 -48
  31. package/plugins/ingestions/web-search/dist/index.js +121 -72
  32. package/plugins/kk/config.example.yaml +13 -0
  33. package/plugins/kk/plugin.json +1 -1
  34. package/plugins/kk/scripts/daily-voice-style.zh.md +52 -0
  35. package/plugins/kk/scripts/kk-workflow-stages.ts +433 -16
  36. package/plugins/kk/skills/publish/SKILL.md +24 -1
  37. package/plugins/kk/skills/xhs-images/SKILL.md +89 -0
  38. package/plugins/kk/skills/xhs-images/references/card-layouts.md +35 -0
  39. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +162 -11
  40. package/plugins/publishings/emdash-pub/dist/index.js +94 -45
  41. package/plugins/publishings/infoq-pub/dist/index.js +94 -45
  42. package/plugins/publishings/juejin-pub/dist/index.js +94 -45
  43. package/plugins/publishings/medium-pub/dist/index.js +94 -45
  44. package/plugins/publishings/podcast-pub/dist/index.js +115 -55
  45. package/plugins/publishings/podcast-pub/src/map.ts +30 -10
  46. package/plugins/publishings/podcast-pub/src/show-notes.ts +6 -1
  47. package/plugins/publishings/qiita-pub/dist/index.js +94 -45
  48. package/plugins/publishings/substack-pub/dist/index.js +94 -45
  49. package/plugins/publishings/surfdash-pub/dist/index.js +99 -63
  50. package/plugins/publishings/surfdash-pub/src/index.ts +10 -1
  51. package/plugins/publishings/wechatmp-pub/dist/index.js +94 -45
  52. package/plugins/publishings/x-pub/dist/index.js +94 -45
  53. package/plugins/publishings/xhs-pub/dist/index.js +8908 -229
  54. package/plugins/publishings/xhs-pub/package.json +1 -0
  55. package/plugins/publishings/xhs-pub/plugin.json +1 -1
  56. package/plugins/publishings/xhs-pub/src/automation-guard.ts +128 -0
  57. package/plugins/publishings/xhs-pub/src/index.ts +753 -24
  58. package/plugins/publishings/xhs-pub/src/profile-check.ts +133 -0
  59. package/plugins/publishings/zenn-pub/dist/index.js +94 -45
  60. package/plugins/sp/lib/env.ts +46 -0
  61. package/plugins/sp/lib/inline-run.generated.mjs +1489 -0
  62. package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
  63. package/plugins/sp/scripts/inline-run-setup.ts +571 -47
  64. package/plugins/sp/scripts/wrapup-drift-probe.mjs +190 -0
  65. package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
  66. package/plugins/sp/scripts/wrapup-steps.mjs +77 -6
  67. package/plugins/sp/scripts/wrapup-steps.ts +91 -5
@@ -6,6 +6,8 @@ export const GEMINI_ASR_DEFAULT_MODEL = 'gemini-3.8-flash';
6
6
  const DEFAULT_BASE_URL = 'https://generativelanguage.googleapis.com';
7
7
  const DEFAULT_PROFILES_PATH = new URL('../profiles.json', import.meta.url).pathname;
8
8
  const TRANSCRIBE_PROMPT = 'Transcribe this audio verbatim. Output only the transcript, no commentary.';
9
+ /** retry-after above this (Google daily-quota 429s: ~70_000s) is never actionable inside a run. */
10
+ const RETRY_AFTER_CAP_SEC = 120;
9
11
  const PLACEHOLDER_VOICE = 'voice_REPLACE_ME';
10
12
 
11
13
  type Env = Record<string, string | undefined>;
@@ -47,6 +49,18 @@ function excerpt(text: string): string {
47
49
  return text.length > 30 ? `${text.slice(0, 30)}…` : text;
48
50
  }
49
51
 
52
+ /**
53
+ * Deadline every network phase so a stalled connection or response body fails loudly instead of
54
+ * hanging forever (AbortSignal.timeout alone left the event loop parked mid-run, 2026-09-24).
55
+ */
56
+ function withDeadline<T>(p: Promise<T>, ms: number): Promise<T> {
57
+ let timer: ReturnType<typeof setTimeout> | undefined;
58
+ const timeout = new Promise<never>((_, reject) => {
59
+ timer = setTimeout(() => reject(new Error(`response body timed out after ${ms}ms`)), ms);
60
+ });
61
+ return Promise.race([p, timeout]).finally(() => clearTimeout(timer));
62
+ }
63
+
50
64
  /**
51
65
  * VoiceboxClient over the Gemini 3.8 TTS REST API, so voice-gen's `processGeneratorIO` pipeline
52
66
  * (verify-retry, speed, concat, QC, MP3) runs unchanged against a hosted backend (ADR-023).
@@ -58,6 +72,10 @@ export function createGeminiVoiceClient(options: GeminiVoiceClientOptions = {}):
58
72
  const sleep = options.sleep ?? ((ms: number) => Bun.sleep(ms));
59
73
  const baseUrl = (env.GOOGLE_BASE_URL || DEFAULT_BASE_URL).replace(/\/+$/, '');
60
74
  const model = env.GEMINI_TTS_MODEL || GEMINI_TTS_DEFAULT_MODEL;
75
+ // Fixed persona style sent for every segment. Gemini re-interprets its short-clip custom voice
76
+ // per style annotation, so per-segment emotions make the persona drift across boundaries
77
+ // (2026-09-24 episode review). When set, this replaces each segment's own instruct.
78
+ const styleOverride = env.GEMINI_TTS_STYLE;
61
79
  const maxAttempts = positiveInt(env.GEMINI_TTS_MAX_ATTEMPTS, 4);
62
80
  const timeoutMs = positiveInt(env.GEMINI_TTS_TIMEOUT_MS, 120_000);
63
81
  const buffered = new Map<string, Uint8Array>();
@@ -69,12 +87,15 @@ export function createGeminiVoiceClient(options: GeminiVoiceClientOptions = {}):
69
87
  for (let attempt = 1; ; attempt++) {
70
88
  let res: Response;
71
89
  try {
72
- res = await doFetch(`${baseUrl}/v1beta/interactions`, {
73
- method: 'POST',
74
- headers: { 'content-type': 'application/json', 'x-goog-api-key': apiKey },
75
- body: JSON.stringify(body),
76
- signal: AbortSignal.timeout(timeoutMs),
77
- });
90
+ res = await withDeadline(
91
+ doFetch(`${baseUrl}/v1beta/interactions`, {
92
+ method: 'POST',
93
+ headers: { 'content-type': 'application/json', 'x-goog-api-key': apiKey },
94
+ body: JSON.stringify(body),
95
+ signal: AbortSignal.timeout(timeoutMs),
96
+ }),
97
+ timeoutMs,
98
+ );
78
99
  } catch (err: unknown) {
79
100
  const msg = err instanceof Error ? err.message : String(err);
80
101
  if (attempt >= maxAttempts)
@@ -82,20 +103,28 @@ export function createGeminiVoiceClient(options: GeminiVoiceClientOptions = {}):
82
103
  await sleep(2000 * 2 ** (attempt - 1));
83
104
  continue;
84
105
  }
85
- if (res.ok) return (await res.json()) as InteractionResponse;
86
- const raw = await res.text();
106
+ if (res.ok) return withDeadline(res.json(), timeoutMs) as Promise<InteractionResponse>;
107
+ const raw = await withDeadline(res.text(), timeoutMs);
87
108
  let apiMessage = raw.slice(0, 300);
88
109
  try {
89
110
  apiMessage = (JSON.parse(raw) as InteractionResponse).error?.message ?? apiMessage;
90
111
  } catch {
91
112
  // non-JSON error body — keep the raw excerpt
92
113
  }
114
+ const retryAfter = Number(res.headers.get('retry-after'));
115
+ // 2026-09-24: three generate runs silently slept ~19h on a daily-quota 429's
116
+ // retry-after 69857 — indistinguishable from a wedge. Cap transient backoff;
117
+ // anything beyond the cap (per-day quota, org throttle) fails the run loudly.
118
+ if (retryAfter > RETRY_AFTER_CAP_SEC) {
119
+ throw new Error(
120
+ `${label}: HTTP ${res.status} quota/reset horizon too far out (retry-after ${retryAfter}s ≈ ${(retryAfter / 3600).toFixed(1)}h): ${apiMessage}`,
121
+ );
122
+ }
93
123
  const retryable = res.status === 429 || res.status >= 500;
94
124
  if (!retryable || attempt >= maxAttempts) {
95
125
  throw new Error(`${label}: HTTP ${res.status} after ${attempt} attempt(s): ${apiMessage}`);
96
126
  }
97
- const retryAfter = Number(res.headers.get('retry-after'));
98
- await sleep(retryAfter > 0 ? retryAfter * 1000 : 2000 * 2 ** (attempt - 1));
127
+ await sleep(retryAfter > 0 ? Math.min(retryAfter, RETRY_AFTER_CAP_SEC) * 1000 : 2000 * 2 ** (attempt - 1));
99
128
  }
100
129
  }
101
130
 
@@ -136,7 +165,8 @@ export function createGeminiVoiceClient(options: GeminiVoiceClientOptions = {}):
136
165
 
137
166
  async generate(body: VoiceboxGenerateBody): Promise<{ id: string }> {
138
167
  const part: Record<string, unknown> = { type: 'text', text: body.text };
139
- if (body.instruct) part.annotations = [{ type: 'speech_metadata', style: body.instruct }];
168
+ const style = styleOverride ?? body.instruct;
169
+ if (style) part.annotations = [{ type: 'speech_metadata', style }];
140
170
  const json = await post(
141
171
  {
142
172
  model,