@gobing-ai/knowledge-kit 0.0.21 → 0.0.23

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 (71) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +161 -142
  3. package/package.json +1 -1
  4. package/plugins/generations/content-gen/dist/index.js +20 -3
  5. package/plugins/generations/core-facts-gen/dist/index.js +20 -3
  6. package/plugins/generations/daily-article-gen/dist/index.js +20 -3
  7. package/plugins/generations/dailynews-gen/dist/index.js +20 -3
  8. package/plugins/generations/episode-plan-gen/dist/index.js +20 -3
  9. package/plugins/generations/gemini-tts/README.md +101 -0
  10. package/plugins/generations/gemini-tts/dist/index.js +23282 -0
  11. package/plugins/generations/gemini-tts/package.json +16 -0
  12. package/plugins/generations/gemini-tts/plugin.json +6 -0
  13. package/plugins/generations/gemini-tts/profiles.json +3 -0
  14. package/plugins/generations/gemini-tts/src/gemini-client.ts +190 -0
  15. package/plugins/generations/gemini-tts/src/index.ts +33 -0
  16. package/plugins/generations/gemini-tts/src/voice-create.ts +180 -0
  17. package/plugins/generations/gemini-tts/tsconfig.json +8 -0
  18. package/plugins/generations/image-gen/dist/index.js +147 -69
  19. package/plugins/generations/image-gen/src/presets.ts +2 -2
  20. package/plugins/generations/image-gen/src/providers/agnes.ts +6 -2
  21. package/plugins/generations/image-gen/src/providers/azure.ts +6 -2
  22. package/plugins/generations/image-gen/src/providers/dashscope.ts +10 -3
  23. package/plugins/generations/image-gen/src/providers/google.ts +70 -29
  24. package/plugins/generations/image-gen/src/providers/huggingface.ts +3 -0
  25. package/plugins/generations/image-gen/src/providers/jimeng.ts +9 -2
  26. package/plugins/generations/image-gen/src/providers/minimax.ts +10 -2
  27. package/plugins/generations/image-gen/src/providers/openai.ts +9 -3
  28. package/plugins/generations/image-gen/src/providers/openrouter.ts +16 -4
  29. package/plugins/generations/image-gen/src/providers/replicate.ts +13 -3
  30. package/plugins/generations/image-gen/src/providers/seedream.ts +4 -1
  31. package/plugins/generations/image-gen/src/providers/timeouts.ts +14 -0
  32. package/plugins/generations/image-gen/src/providers/types.ts +10 -0
  33. package/plugins/generations/image-gen/src/providers/zai.ts +4 -1
  34. package/plugins/generations/news-report-gen/dist/index.js +20 -3
  35. package/plugins/generations/voice-gen/dist/index.js +38 -12
  36. package/plugins/generations/voice-gen/package.json +3 -0
  37. package/plugins/generations/voice-gen/src/index.ts +2 -1
  38. package/plugins/generations/voice-gen/src/voicebox-client.ts +20 -5
  39. package/plugins/generations/voice-gen/src/voicebox-server.ts +2 -1
  40. package/plugins/ingestions/aihot-ingest/dist/index.js +25 -5
  41. package/plugins/ingestions/aihot-ingest/src/client.ts +5 -0
  42. package/plugins/ingestions/horizon-ingest/dist/index.js +20 -3
  43. package/plugins/ingestions/last30days-ingest/dist/index.js +20 -3
  44. package/plugins/ingestions/web-search/dist/index.js +22 -3
  45. package/plugins/ingestions/web-search/src/index.ts +4 -0
  46. package/plugins/kk/plugin.json +1 -1
  47. package/plugins/kk/scripts/kk-workflow-stages.ts +40 -8
  48. package/plugins/kk/scripts/render-md.ts +7 -1
  49. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +2 -2
  50. package/plugins/publishings/emdash-pub/dist/index.js +76 -19
  51. package/plugins/publishings/emdash-pub/src/index.ts +4 -0
  52. package/plugins/publishings/infoq-pub/dist/index.js +74 -21
  53. package/plugins/publishings/juejin-pub/dist/index.js +74 -21
  54. package/plugins/publishings/medium-pub/dist/index.js +77 -19
  55. package/plugins/publishings/medium-pub/src/index.ts +5 -0
  56. package/plugins/publishings/podcast-pub/dist/index.js +130 -34
  57. package/plugins/publishings/podcast-pub/src/index.ts +20 -5
  58. package/plugins/publishings/podcast-pub/src/map.ts +11 -0
  59. package/plugins/publishings/podcast-pub/src/show-notes.ts +66 -13
  60. package/plugins/publishings/qiita-pub/dist/index.js +75 -18
  61. package/plugins/publishings/qiita-pub/src/index.ts +4 -0
  62. package/plugins/publishings/substack-pub/dist/index.js +74 -21
  63. package/plugins/publishings/surfdash-pub/dist/index.js +99 -62
  64. package/plugins/publishings/surfdash-pub/src/index.ts +60 -19
  65. package/plugins/publishings/wechatmp-pub/dist/index.js +79 -22
  66. package/plugins/publishings/wechatmp-pub/src/index.ts +12 -3
  67. package/plugins/publishings/x-pub/dist/index.js +56 -37
  68. package/plugins/publishings/x-pub/src/index.ts +4 -0
  69. package/plugins/publishings/xhs-pub/dist/index.js +74 -21
  70. package/plugins/publishings/zenn-pub/dist/index.js +103 -25
  71. package/plugins/publishings/zenn-pub/src/index.ts +43 -9
@@ -21781,6 +21781,22 @@ var ResultSchema = exports_external.object({
21781
21781
  error: exports_external.string().optional(),
21782
21782
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21783
21783
  });
21784
+ var TargetOutcomeSchema = exports_external.object({
21785
+ target: exports_external.string(),
21786
+ ok: exports_external.boolean(),
21787
+ status: exports_external.enum(["published", "failed", "skipped"]),
21788
+ url: exports_external.string().optional(),
21789
+ id: exports_external.string().optional(),
21790
+ error: exports_external.string().optional(),
21791
+ durationMs: exports_external.number().optional(),
21792
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21793
+ });
21794
+ var AggregateResultSchema = exports_external.object({
21795
+ ok: exports_external.boolean(),
21796
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21797
+ targets: exports_external.array(TargetOutcomeSchema),
21798
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21799
+ });
21784
21800
  var DocListSchema = exports_external.array(DocSchema);
21785
21801
  var omniVoiceGenContentSchema = ContentSchema.extend({
21786
21802
  format: exports_external.literal("audio"),
@@ -21809,14 +21825,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21809
21825
  // ../../packages/kk-core/src/manifest.ts
21810
21826
  init_zod();
21811
21827
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21812
- var PluginManifestSchema = exports_external.object({
21828
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21829
+ var PluginManifestSchema = exports_external.looseObject({
21813
21830
  name: exports_external.string().min(1),
21814
21831
  kind: PluginKindSchema,
21815
21832
  entry: exports_external.string().min(1),
21816
21833
  version: exports_external.string().optional(),
21817
21834
  description: exports_external.string().optional(),
21818
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21819
- }).passthrough();
21835
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21836
+ });
21820
21837
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21821
21838
  init_file_system_node();
21822
21839
  init_config();
@@ -22249,16 +22266,22 @@ async function auditVoiceSegments(script, segmentWavs, segmentMetadata, client)
22249
22266
  }
22250
22267
 
22251
22268
  // ../../plugins/generations/voice-gen/src/voicebox-client.ts
22269
+ function resolveVoiceboxTimeoutMs() {
22270
+ const raw = process.env.VOICEBOX_TIMEOUT_MS;
22271
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
22272
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 600000;
22273
+ }
22252
22274
  function createVoiceboxClient(options = {}) {
22253
22275
  const rawUrl = options.url || process.env.VOICEBOX_URL || "http://127.0.0.1:17493";
22254
22276
  const url2 = rawUrl.replace(/\/+$/, "");
22255
22277
  const customFetch = options.fetch ?? globalThis.fetch;
22256
22278
  const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
22279
+ const requestTimeoutMs = resolveVoiceboxTimeoutMs();
22257
22280
  return {
22258
22281
  url: url2,
22259
22282
  async health() {
22260
22283
  try {
22261
- const res = await customFetch(`${url2}/health`);
22284
+ const res = await customFetch(`${url2}/health`, { signal: AbortSignal.timeout(requestTimeoutMs) });
22262
22285
  if (!res.ok) {
22263
22286
  throw new Error(`HTTP ${res.status} ${res.statusText}`);
22264
22287
  }
@@ -22270,7 +22293,7 @@ function createVoiceboxClient(options = {}) {
22270
22293
  async resolveProfile(nameOrId) {
22271
22294
  let res;
22272
22295
  try {
22273
- res = await customFetch(`${url2}/profiles`);
22296
+ res = await customFetch(`${url2}/profiles`, { signal: AbortSignal.timeout(requestTimeoutMs) });
22274
22297
  } catch (err) {
22275
22298
  const reason = err instanceof Error ? err.message : String(err);
22276
22299
  throw new Error(`Voicebox /profiles request failed at ${url2}: ${reason}`);
@@ -22303,7 +22326,8 @@ function createVoiceboxClient(options = {}) {
22303
22326
  headers: {
22304
22327
  "Content-Type": "application/json"
22305
22328
  },
22306
- body: JSON.stringify(body)
22329
+ body: JSON.stringify(body),
22330
+ signal: AbortSignal.timeout(requestTimeoutMs)
22307
22331
  });
22308
22332
  } catch (err) {
22309
22333
  const reason = err instanceof Error ? err.message : String(err);
@@ -22335,7 +22359,7 @@ function createVoiceboxClient(options = {}) {
22335
22359
  while (true) {
22336
22360
  let res;
22337
22361
  try {
22338
- res = await customFetch(`${url2}/history/${id}`);
22362
+ res = await customFetch(`${url2}/history/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
22339
22363
  } catch (err) {
22340
22364
  const reason = err instanceof Error ? err.message : String(err);
22341
22365
  throw new Error(`Voicebox /history/${id} request failed at ${url2}: ${reason}`);
@@ -22369,7 +22393,7 @@ function createVoiceboxClient(options = {}) {
22369
22393
  async downloadAudio(id) {
22370
22394
  let res;
22371
22395
  try {
22372
- res = await customFetch(`${url2}/audio/${id}`);
22396
+ res = await customFetch(`${url2}/audio/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
22373
22397
  } catch (err) {
22374
22398
  const reason = err instanceof Error ? err.message : String(err);
22375
22399
  throw new Error(`Voicebox /audio/${id} request failed at ${url2}: ${reason}`);
@@ -22394,7 +22418,8 @@ function createVoiceboxClient(options = {}) {
22394
22418
  try {
22395
22419
  res = await customFetch(`${url2}/transcribe`, {
22396
22420
  method: "POST",
22397
- body: formData
22421
+ body: formData,
22422
+ signal: AbortSignal.timeout(requestTimeoutMs)
22398
22423
  });
22399
22424
  } catch (err) {
22400
22425
  const reason = err instanceof Error ? err.message : String(err);
@@ -22423,7 +22448,7 @@ var POLL_MS = 500;
22423
22448
  var LOG_PATH = "/tmp/voicebox-server.log";
22424
22449
  async function probeVoiceboxHealth(url2, customFetch) {
22425
22450
  try {
22426
- return (await customFetch(`${url2}/health`)).ok;
22451
+ return (await customFetch(`${url2}/health`, { signal: AbortSignal.timeout(resolveVoiceboxTimeoutMs()) })).ok;
22427
22452
  } catch {
22428
22453
  return false;
22429
22454
  }
@@ -22871,7 +22896,7 @@ No documents provided for generation.`,
22871
22896
  format: "markdown",
22872
22897
  references: []
22873
22898
  };
22874
- async function processGeneratorIO(inputPath, outputPath, clientOverride, transcodeMp3) {
22899
+ async function processGeneratorIO(inputPath, outputPath, clientOverride, transcodeMp3, generator = "kk:voice-gen") {
22875
22900
  const fs = createNodeFileSystem();
22876
22901
  const outDir = dirname2(outputPath);
22877
22902
  const outStem = basename(outputPath, extname(outputPath));
@@ -23038,7 +23063,7 @@ async function processGeneratorIO(inputPath, outputPath, clientOverride, transco
23038
23063
  await fs.ensureDir(outDir);
23039
23064
  await Bun.write(audioPath, concatenatedWav);
23040
23065
  const metadata = {
23041
- generator: "kk:voice-gen",
23066
+ generator,
23042
23067
  audioPath,
23043
23068
  duration: totalDuration,
23044
23069
  segments: segmentMetadata
@@ -23097,6 +23122,7 @@ export {
23097
23122
  validateVoiceScript,
23098
23123
  transcriptionFidelity,
23099
23124
  transcodeWavToMp3,
23125
+ resolveVoiceboxTimeoutMs,
23100
23126
  resolveInstruct,
23101
23127
  resolveEffectsChain,
23102
23128
  processGeneratorIO,
@@ -2,6 +2,9 @@
2
2
  "name": "@gobing-ai/voice-gen",
3
3
  "type": "module",
4
4
  "private": true,
5
+ "exports": {
6
+ ".": "./src/index.ts"
7
+ },
5
8
  "scripts": {
6
9
  "typecheck": "tsc --noEmit"
7
10
  },
@@ -43,6 +43,7 @@ export async function processGeneratorIO(
43
43
  outputPath: string,
44
44
  clientOverride?: VoiceboxClient,
45
45
  transcodeMp3?: Mp3Transcoder,
46
+ generator = 'kk:voice-gen',
46
47
  ): Promise<void> {
47
48
  const fs = createNodeFileSystem();
48
49
  const outDir = dirname(outputPath);
@@ -317,7 +318,7 @@ export async function processGeneratorIO(
317
318
  await Bun.write(audioPath, concatenatedWav);
318
319
 
319
320
  const metadata: Record<string, unknown> = {
320
- generator: 'kk:voice-gen',
321
+ generator,
321
322
  audioPath,
322
323
  duration: totalDuration,
323
324
  segments: segmentMetadata,
@@ -44,7 +44,8 @@ export interface VoiceboxClient {
44
44
  pollMs?: number,
45
45
  ): Promise<{ status: 'completed' | 'failed'; duration?: number; error?: string }>;
46
46
  downloadAudio(id: string): Promise<Uint8Array>;
47
- transcribe(audio: Uint8Array, language?: string): Promise<{ text: string; duration?: number }>;
47
+ /** Optional: backends without ASR omit it; callers skip fidelity/repetition checks. */
48
+ transcribe?(audio: Uint8Array, language?: string): Promise<{ text: string; duration?: number }>;
48
49
  }
49
50
 
50
51
  export interface VoiceboxClientOptions {
@@ -56,18 +57,30 @@ export interface VoiceboxClientOptions {
56
57
  /**
57
58
  * Creates a client for the Voicebox local REST API.
58
59
  */
60
+ /**
61
+ * Per-request timeout (ms): `VOICEBOX_TIMEOUT_MS` when set to a positive number, else 600 000.
62
+ * Voice generation is slow, so the default is generous — but every call must be bounded, because
63
+ * Bun's `fetch` has no overall request deadline without a `signal` (R5).
64
+ */
65
+ export function resolveVoiceboxTimeoutMs(): number {
66
+ const raw = process.env.VOICEBOX_TIMEOUT_MS;
67
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
68
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 600_000;
69
+ }
70
+
59
71
  export function createVoiceboxClient(options: VoiceboxClientOptions = {}): VoiceboxClient {
60
72
  const rawUrl = options.url || process.env.VOICEBOX_URL || 'http://127.0.0.1:17493';
61
73
  const url = rawUrl.replace(/\/+$/, '');
62
74
  const customFetch = options.fetch ?? globalThis.fetch;
63
75
  const sleep = options.sleep ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms)));
76
+ const requestTimeoutMs = resolveVoiceboxTimeoutMs();
64
77
 
65
78
  return {
66
79
  url,
67
80
 
68
81
  async health(): Promise<void> {
69
82
  try {
70
- const res = await customFetch(`${url}/health`);
83
+ const res = await customFetch(`${url}/health`, { signal: AbortSignal.timeout(requestTimeoutMs) });
71
84
  if (!res.ok) {
72
85
  throw new Error(`HTTP ${res.status} ${res.statusText}`);
73
86
  }
@@ -82,7 +95,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
82
95
  async resolveProfile(nameOrId: string): Promise<VoiceboxProfile> {
83
96
  let res: Response;
84
97
  try {
85
- res = await customFetch(`${url}/profiles`);
98
+ res = await customFetch(`${url}/profiles`, { signal: AbortSignal.timeout(requestTimeoutMs) });
86
99
  } catch (err: unknown) {
87
100
  const reason = err instanceof Error ? err.message : String(err);
88
101
  throw new Error(`Voicebox /profiles request failed at ${url}: ${reason}`);
@@ -123,6 +136,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
123
136
  'Content-Type': 'application/json',
124
137
  },
125
138
  body: JSON.stringify(body),
139
+ signal: AbortSignal.timeout(requestTimeoutMs),
126
140
  });
127
141
  } catch (err: unknown) {
128
142
  const reason = err instanceof Error ? err.message : String(err);
@@ -170,7 +184,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
170
184
  while (true) {
171
185
  let res: Response;
172
186
  try {
173
- res = await customFetch(`${url}/history/${id}`);
187
+ res = await customFetch(`${url}/history/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
174
188
  } catch (err: unknown) {
175
189
  const reason = err instanceof Error ? err.message : String(err);
176
190
  throw new Error(`Voicebox /history/${id} request failed at ${url}: ${reason}`);
@@ -212,7 +226,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
212
226
  async downloadAudio(id: string): Promise<Uint8Array> {
213
227
  let res: Response;
214
228
  try {
215
- res = await customFetch(`${url}/audio/${id}`);
229
+ res = await customFetch(`${url}/audio/${id}`, { signal: AbortSignal.timeout(requestTimeoutMs) });
216
230
  } catch (err: unknown) {
217
231
  const reason = err instanceof Error ? err.message : String(err);
218
232
  throw new Error(`Voicebox /audio/${id} request failed at ${url}: ${reason}`);
@@ -242,6 +256,7 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
242
256
  res = await customFetch(`${url}/transcribe`, {
243
257
  method: 'POST',
244
258
  body: formData,
259
+ signal: AbortSignal.timeout(requestTimeoutMs),
245
260
  });
246
261
  } catch (err: unknown) {
247
262
  const reason = err instanceof Error ? err.message : String(err);
@@ -3,6 +3,7 @@ import { existsSync, openSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { echoError } from '@gobing-ai/ts-utils';
6
+ import { resolveVoiceboxTimeoutMs } from './voicebox-client';
6
7
 
7
8
  /** Boot wait / poll cadence for a freshly spawned local server (Voicebox cold start ≈ 2-5s). */
8
9
  const BOOT_WAIT_MS = 30_000;
@@ -23,7 +24,7 @@ export interface VoiceboxServerOptions {
23
24
 
24
25
  async function probeVoiceboxHealth(url: string, customFetch: typeof fetch): Promise<boolean> {
25
26
  try {
26
- return (await customFetch(`${url}/health`)).ok;
27
+ return (await customFetch(`${url}/health`, { signal: AbortSignal.timeout(resolveVoiceboxTimeoutMs()) })).ok;
27
28
  } catch {
28
29
  return false;
29
30
  }
@@ -21781,6 +21781,22 @@ var ResultSchema = exports_external.object({
21781
21781
  error: exports_external.string().optional(),
21782
21782
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21783
21783
  });
21784
+ var TargetOutcomeSchema = exports_external.object({
21785
+ target: exports_external.string(),
21786
+ ok: exports_external.boolean(),
21787
+ status: exports_external.enum(["published", "failed", "skipped"]),
21788
+ url: exports_external.string().optional(),
21789
+ id: exports_external.string().optional(),
21790
+ error: exports_external.string().optional(),
21791
+ durationMs: exports_external.number().optional(),
21792
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21793
+ });
21794
+ var AggregateResultSchema = exports_external.object({
21795
+ ok: exports_external.boolean(),
21796
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21797
+ targets: exports_external.array(TargetOutcomeSchema),
21798
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21799
+ });
21784
21800
  var DocListSchema = exports_external.array(DocSchema);
21785
21801
  var omniVoiceGenContentSchema = ContentSchema.extend({
21786
21802
  format: exports_external.literal("audio"),
@@ -21809,14 +21825,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21809
21825
  // ../../packages/kk-core/src/manifest.ts
21810
21826
  init_zod();
21811
21827
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21812
- var PluginManifestSchema = exports_external.object({
21828
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21829
+ var PluginManifestSchema = exports_external.looseObject({
21813
21830
  name: exports_external.string().min(1),
21814
21831
  kind: PluginKindSchema,
21815
21832
  entry: exports_external.string().min(1),
21816
21833
  version: exports_external.string().optional(),
21817
21834
  description: exports_external.string().optional(),
21818
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21819
- }).passthrough();
21835
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21836
+ });
21820
21837
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21821
21838
  init_file_system_node();
21822
21839
  init_config();
@@ -21911,6 +21928,7 @@ init_zod();
21911
21928
 
21912
21929
  // ../../plugins/ingestions/aihot-ingest/src/client.ts
21913
21930
  init_zod();
21931
+ var REQUEST_TIMEOUT_MS = 120000;
21914
21932
  var AIHOT_BASE_URL = "https://aihot.virxact.com";
21915
21933
  var DEFAULT_AIHOT_USER_AGENT = "aihot-ingest/1.0.0";
21916
21934
  var AihotItemSchema = exports_external.object({
@@ -21996,7 +22014,8 @@ class AihotClient {
21996
22014
  headers: {
21997
22015
  Accept: "application/json",
21998
22016
  "User-Agent": this.userAgent
21999
- }
22017
+ },
22018
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
22000
22019
  });
22001
22020
  if (!res.ok) {
22002
22021
  const errBody = (await res.text()).slice(0, 1000);
@@ -22019,7 +22038,8 @@ class AihotClient {
22019
22038
  headers: {
22020
22039
  Accept: "application/json",
22021
22040
  "User-Agent": this.userAgent
22022
- }
22041
+ },
22042
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
22023
22043
  });
22024
22044
  if (!res.ok) {
22025
22045
  const errBody = (await res.text()).slice(0, 1000);
@@ -1,6 +1,9 @@
1
1
  import { echoError } from '@gobing-ai/ts-utils';
2
2
  import { z } from 'zod';
3
3
 
4
+ /** Per-request timeout (ms) for aihot HTTP calls — Bun's `fetch` has no default deadline (R5). */
5
+ const REQUEST_TIMEOUT_MS = 120_000;
6
+
4
7
  export const AIHOT_BASE_URL = 'https://aihot.virxact.com';
5
8
  export const DEFAULT_AIHOT_USER_AGENT = 'aihot-ingest/1.0.0';
6
9
 
@@ -123,6 +126,7 @@ export class AihotClient {
123
126
  Accept: 'application/json',
124
127
  'User-Agent': this.userAgent,
125
128
  },
129
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
126
130
  });
127
131
 
128
132
  if (!res.ok) {
@@ -152,6 +156,7 @@ export class AihotClient {
152
156
  Accept: 'application/json',
153
157
  'User-Agent': this.userAgent,
154
158
  },
159
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
155
160
  });
156
161
 
157
162
  if (!res.ok) {
@@ -21782,6 +21782,22 @@ var ResultSchema = exports_external.object({
21782
21782
  error: exports_external.string().optional(),
21783
21783
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21784
21784
  });
21785
+ var TargetOutcomeSchema = exports_external.object({
21786
+ target: exports_external.string(),
21787
+ ok: exports_external.boolean(),
21788
+ status: exports_external.enum(["published", "failed", "skipped"]),
21789
+ url: exports_external.string().optional(),
21790
+ id: exports_external.string().optional(),
21791
+ error: exports_external.string().optional(),
21792
+ durationMs: exports_external.number().optional(),
21793
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21794
+ });
21795
+ var AggregateResultSchema = exports_external.object({
21796
+ ok: exports_external.boolean(),
21797
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21798
+ targets: exports_external.array(TargetOutcomeSchema),
21799
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21800
+ });
21785
21801
  var DocListSchema = exports_external.array(DocSchema);
21786
21802
  var omniVoiceGenContentSchema = ContentSchema.extend({
21787
21803
  format: exports_external.literal("audio"),
@@ -21810,14 +21826,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21810
21826
  // ../../packages/kk-core/src/manifest.ts
21811
21827
  init_zod();
21812
21828
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21813
- var PluginManifestSchema = exports_external.object({
21829
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21830
+ var PluginManifestSchema = exports_external.looseObject({
21814
21831
  name: exports_external.string().min(1),
21815
21832
  kind: PluginKindSchema,
21816
21833
  entry: exports_external.string().min(1),
21817
21834
  version: exports_external.string().optional(),
21818
21835
  description: exports_external.string().optional(),
21819
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21820
- }).passthrough();
21836
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21837
+ });
21821
21838
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21822
21839
  init_file_system_node();
21823
21840
  init_config();
@@ -21783,6 +21783,22 @@ var ResultSchema = exports_external.object({
21783
21783
  error: exports_external.string().optional(),
21784
21784
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21785
21785
  });
21786
+ var TargetOutcomeSchema = exports_external.object({
21787
+ target: exports_external.string(),
21788
+ ok: exports_external.boolean(),
21789
+ status: exports_external.enum(["published", "failed", "skipped"]),
21790
+ url: exports_external.string().optional(),
21791
+ id: exports_external.string().optional(),
21792
+ error: exports_external.string().optional(),
21793
+ durationMs: exports_external.number().optional(),
21794
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21795
+ });
21796
+ var AggregateResultSchema = exports_external.object({
21797
+ ok: exports_external.boolean(),
21798
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21799
+ targets: exports_external.array(TargetOutcomeSchema),
21800
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21801
+ });
21786
21802
  var DocListSchema = exports_external.array(DocSchema);
21787
21803
  var omniVoiceGenContentSchema = ContentSchema.extend({
21788
21804
  format: exports_external.literal("audio"),
@@ -21811,14 +21827,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21811
21827
  // ../../packages/kk-core/src/manifest.ts
21812
21828
  init_zod();
21813
21829
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21814
- var PluginManifestSchema = exports_external.object({
21830
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21831
+ var PluginManifestSchema = exports_external.looseObject({
21815
21832
  name: exports_external.string().min(1),
21816
21833
  kind: PluginKindSchema,
21817
21834
  entry: exports_external.string().min(1),
21818
21835
  version: exports_external.string().optional(),
21819
21836
  description: exports_external.string().optional(),
21820
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21821
- }).passthrough();
21837
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21838
+ });
21822
21839
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21823
21840
  init_file_system_node();
21824
21841
  init_config();
@@ -21782,6 +21782,22 @@ var ResultSchema = exports_external.object({
21782
21782
  error: exports_external.string().optional(),
21783
21783
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21784
21784
  });
21785
+ var TargetOutcomeSchema = exports_external.object({
21786
+ target: exports_external.string(),
21787
+ ok: exports_external.boolean(),
21788
+ status: exports_external.enum(["published", "failed", "skipped"]),
21789
+ url: exports_external.string().optional(),
21790
+ id: exports_external.string().optional(),
21791
+ error: exports_external.string().optional(),
21792
+ durationMs: exports_external.number().optional(),
21793
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21794
+ });
21795
+ var AggregateResultSchema = exports_external.object({
21796
+ ok: exports_external.boolean(),
21797
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21798
+ targets: exports_external.array(TargetOutcomeSchema),
21799
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21800
+ });
21785
21801
  var DocListSchema = exports_external.array(DocSchema);
21786
21802
  var omniVoiceGenContentSchema = ContentSchema.extend({
21787
21803
  format: exports_external.literal("audio"),
@@ -21810,14 +21826,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21810
21826
  // ../../packages/kk-core/src/manifest.ts
21811
21827
  init_zod();
21812
21828
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21813
- var PluginManifestSchema = exports_external.object({
21829
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21830
+ var PluginManifestSchema = exports_external.looseObject({
21814
21831
  name: exports_external.string().min(1),
21815
21832
  kind: PluginKindSchema,
21816
21833
  entry: exports_external.string().min(1),
21817
21834
  version: exports_external.string().optional(),
21818
21835
  description: exports_external.string().optional(),
21819
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21820
- }).passthrough();
21836
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21837
+ });
21821
21838
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21822
21839
  init_file_system_node();
21823
21840
  init_config();
@@ -24042,6 +24059,7 @@ async function initializeLogger(options = {}) {
24042
24059
  }
24043
24060
  // ../../plugins/ingestions/web-search/src/index.ts
24044
24061
  var log = getLogger2("kk.ingestion.web-search");
24062
+ var REQUEST_TIMEOUT_MS = 120000;
24045
24063
  var FIXTURE_ENTRIES = [
24046
24064
  {
24047
24065
  sourceUri: "https://example.org/research/storm-overview",
@@ -24101,6 +24119,7 @@ async function searchFirecrawl(input, deps) {
24101
24119
  "Content-Type": "application/json",
24102
24120
  Authorization: `Bearer ${key}`
24103
24121
  },
24122
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
24104
24123
  body: JSON.stringify({
24105
24124
  query: input.topic,
24106
24125
  limit: input.maxResults,
@@ -8,6 +8,9 @@ import { echoError } from '@gobing-ai/ts-utils';
8
8
 
9
9
  const log = getLogger('kk.ingestion.web-search');
10
10
 
11
+ /** Per-request timeout (ms) for the Firecrawl call — Bun's `fetch` has no default deadline (R5). */
12
+ const REQUEST_TIMEOUT_MS = 120_000;
13
+
11
14
  /** Validated `--in` input per the 0054 contract (`topic` required; `maxResults`/`fixture` optional). */
12
15
  interface InInput {
13
16
  topic: string;
@@ -136,6 +139,7 @@ export async function searchFirecrawl(input: InInput, deps: SearchDeps): Promise
136
139
  'Content-Type': 'application/json',
137
140
  Authorization: `Bearer ${key}`,
138
141
  },
142
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
139
143
  body: JSON.stringify({
140
144
  query: input.topic,
141
145
  limit: input.maxResults,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "kk",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "knowledge-kit Claude Code plugin: skills, commands, subagents, hooks, and rules"
5
5
  }
@@ -54,7 +54,7 @@ import {
54
54
  writeFileSync,
55
55
  } from 'node:fs';
56
56
  import { homedir } from 'node:os';
57
- import { basename, dirname, join, resolve } from 'node:path';
57
+ import { basename, dirname, join, relative, resolve } from 'node:path';
58
58
 
59
59
  const SCRIPTS_DIR = import.meta.dir;
60
60
  const VALIDATE_SIDECAR = 'validate-voicescript.ts';
@@ -965,7 +965,11 @@ function dailyGenerate(args: string[]): void {
965
965
  const [workDir = '', runDate = '', pluginsPath = '', transcodeMp3 = '', vdriver = ''] = args;
966
966
  // 20260917 review: the workflow picks a voice driver by short name; both drivers' envs are
967
967
  // passed unconditionally so switching `vdriver` needs no shell changes. Unknown -> fail loud.
968
- const VOICE_DRIVERS: Record<string, string> = { ominivoice: 'omni-voice-gen', voicebox: 'voice-gen' };
968
+ const VOICE_DRIVERS: Record<string, string> = {
969
+ ominivoice: 'omni-voice-gen',
970
+ voicebox: 'voice-gen',
971
+ gemini: 'gemini-tts',
972
+ };
969
973
  const voiceGenerator = VOICE_DRIVERS[vdriver];
970
974
  if (!voiceGenerator) {
971
975
  failWith(
@@ -1336,6 +1340,17 @@ function dailyPatchSurfdash(args: string[]): void {
1336
1340
  const postPath = (sd.metadata as Record<string, unknown> | undefined)?.postPath;
1337
1341
  if (typeof postPath !== 'string' || postPath === '')
1338
1342
  failWith(1, 'patch-surfdash: surfdash result carries no postPath');
1343
+ // Refuse before anything is written: surfdash's deploy.yml publishes from main, so a commit
1344
+ // on any other branch is invisible to production. Placed here (after the input checks) so a
1345
+ // refusal leaves the working tree untouched.
1346
+ const head = spawnSync('git', ['-C', surfdashRoot, 'rev-parse', '--abbrev-ref', 'HEAD'])
1347
+ .stdout?.toString()
1348
+ .trim();
1349
+ if (head !== 'main')
1350
+ failWith(1, `patch-surfdash: refusing to commit on '${head}' — surfdash deploys from main`);
1351
+ // Paths this run actually wrote, relative to surfdashRoot. `git add`/`commit` take these as a
1352
+ // pathspec so the operator's unrelated staged work is never swept into the commit.
1353
+ const written: string[] = [];
1339
1354
  const slugDir = dirname(postPath);
1340
1355
  const showNotesUrl = typeof pod.url === 'string' ? pod.url : '';
1341
1356
  const coverUrl = ((pod.metadata as Record<string, unknown> | undefined)?.imageUrl as string | undefined) ?? '';
@@ -1366,10 +1381,19 @@ function dailyPatchSurfdash(args: string[]): void {
1366
1381
  // Upsert a single-line `key: 'value'`; the regex consumes folded-scalar continuation
1367
1382
  // lines (`og_image: >-\n https://...`) so multi-line publish output is replaced whole.
1368
1383
  const upsertKey = (src: string, key: string, value: string): string => {
1369
- const line = `${key}: '${value}'`;
1384
+ // YAML single-quoted scalars escape `'` as `''`; the replacement is a function so
1385
+ // `$&`/`$1`/`$$` in the value are never expanded. Scope the match to the frontmatter
1386
+ // (recomputed per call, since each upsert shifts offsets) so a body line starting with
1387
+ // `image:` is not rewritten.
1388
+ const end = src.indexOf('\n---', 3);
1389
+ const fm = src.slice(0, end);
1390
+ const body = src.slice(end);
1391
+ const line = `${key}: '${value.replaceAll("'", "''")}'`;
1370
1392
  const re = new RegExp(`^${key}:.*(?:\\n[ \\t]+.*)*`, 'm');
1371
- if (re.test(src)) return src.replace(re, line);
1372
- return src.replace(/^publishDate: .*$/m, (m0) => `${m0}\n${line}`);
1393
+ const next = re.test(fm)
1394
+ ? fm.replace(re, () => line)
1395
+ : fm.replace(/^publishDate: .*$/m, (m0) => `${m0}\n${line}`);
1396
+ return next + body;
1373
1397
  };
1374
1398
  if (coverUrl !== '') {
1375
1399
  // 20260919 prod feedback: the podcast-hosted cover URL wins even when surfdash-pub
@@ -1383,6 +1407,7 @@ function dailyPatchSurfdash(args: string[]): void {
1383
1407
  const assets = join(dir, 'assets');
1384
1408
  mkdirSync(assets, { recursive: true });
1385
1409
  copyFileSync(localCover, join(assets, 'cover.png'));
1410
+ written.push(relative(surfdashRoot, join(assets, 'cover.png')));
1386
1411
  md = upsertKey(md, 'image', './assets/cover.png');
1387
1412
  md = upsertKey(md, 'og_image', './assets/cover.png');
1388
1413
  }
@@ -1392,6 +1417,7 @@ function dailyPatchSurfdash(args: string[]): void {
1392
1417
  }
1393
1418
  if (md !== readFileSync(indexMd, 'utf-8')) {
1394
1419
  sted('write', indexMd, () => writeFileSync(indexMd, md));
1420
+ written.push(relative(surfdashRoot, indexMd));
1395
1421
  changed++;
1396
1422
  }
1397
1423
  }
@@ -1403,9 +1429,15 @@ function dailyPatchSurfdash(args: string[]): void {
1403
1429
  const r = spawnSync('git', ['-C', surfdashRoot, ...a]);
1404
1430
  if (r.status !== 0) failWith(1, `patch-surfdash: git ${a[0]} failed: ${r.stderr?.toString().trim()}`);
1405
1431
  };
1406
- git('add', 'content/posts/articles');
1407
- git('commit', '-m', `feat: cover + podcast cross-link for ${basename(slugDir)} (kk daily patch)`);
1408
- if (process.env.SURFDASH_AUTO_PUSH !== '0') git('push');
1432
+ git('add', '--', ...written);
1433
+ git(
1434
+ 'commit',
1435
+ '-m',
1436
+ `feat: cover + podcast cross-link for ${basename(slugDir)} (kk daily patch)`,
1437
+ '--',
1438
+ ...written,
1439
+ );
1440
+ if (process.env.SURFDASH_AUTO_PUSH !== '0') git('push', 'origin', 'main');
1409
1441
  console.log(
1410
1442
  `patch-surfdash: patched ${changed} post(s), committed${process.env.SURFDASH_AUTO_PUSH !== '0' ? ' + pushed' : ' (push skipped: SURFDASH_AUTO_PUSH=0)'}`,
1411
1443
  );