@gobing-ai/knowledge-kit 0.1.4 → 0.1.6

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 (75) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/board/collect/index.css +447 -0
  3. package/dist/board/collect/index.js +2505 -453
  4. package/dist/board/daily-voice/index.css +447 -0
  5. package/dist/board/daily-voice/index.js +415 -8
  6. package/dist/board/itc/index.css +447 -0
  7. package/dist/board/itc/index.js +415 -8
  8. package/dist/index.js +494 -136
  9. package/package.json +6 -5
  10. package/plugins/generations/content-gen/dist/index.js +9 -9
  11. package/plugins/generations/core-facts-gen/dist/index.js +12 -12
  12. package/plugins/generations/daily-article-gen/dist/index.js +15 -13
  13. package/plugins/generations/daily-article-gen/src/index.ts +5 -3
  14. package/plugins/generations/dailynews-gen/dist/index.js +9 -9
  15. package/plugins/generations/episode-plan-gen/dist/index.js +12 -12
  16. package/plugins/generations/gemini-tts/dist/index.js +9 -9
  17. package/plugins/generations/image-gen/dist/index.js +28 -12
  18. package/plugins/generations/image-gen/src/compose/card.ts +19 -3
  19. package/plugins/generations/news-report-gen/dist/index.js +12 -12
  20. package/plugins/generations/voice-gen/dist/index.js +9 -9
  21. package/plugins/generations/voxcpm-tts/README.md +31 -0
  22. package/plugins/generations/voxcpm-tts/dist/index.js +9 -9
  23. package/plugins/generations/voxcpm-tts/scripts/probe-long-render.py +134 -0
  24. package/plugins/ingestions/aihot-ingest/dist/index.js +12 -12
  25. package/plugins/ingestions/horizon-ingest/dist/index.js +12 -12
  26. package/plugins/ingestions/karakeep-local/dist/index.js +13 -13
  27. package/plugins/ingestions/last30days-ingest/dist/index.js +12 -12
  28. package/plugins/ingestions/web-search/dist/index.js +10 -10
  29. package/plugins/kk/decisions/kk-podcast.yaml +44 -0
  30. package/plugins/kk/decisions/kk-safety.yaml +46 -0
  31. package/plugins/kk/plugin.json +1 -1
  32. package/plugins/kk/scripts/audio-quality.ts +635 -0
  33. package/plugins/kk/scripts/daily-stages.ts +163 -0
  34. package/plugins/kk/scripts/kk-workflow-stages.ts +34 -0
  35. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +25 -9
  36. package/plugins/kk/workflows/kk-daily-safety.yaml +37 -10
  37. package/plugins/kk/workflows/kk-solo-podcast.yaml +65 -1
  38. package/plugins/publishings/bilibili-pub/dist/index.js +22 -22
  39. package/plugins/publishings/bilibili-pub/dist/profile-check.js +22 -22
  40. package/plugins/publishings/cnblogs-pub/dist/index.js +22 -22
  41. package/plugins/publishings/cnblogs-pub/dist/profile-check.js +22 -22
  42. package/plugins/publishings/csdn-pub/dist/index.js +22 -22
  43. package/plugins/publishings/csdn-pub/dist/profile-check.js +22 -22
  44. package/plugins/publishings/emdash-pub/dist/index.js +9 -9
  45. package/plugins/publishings/infoq-pub/dist/index.js +22 -22
  46. package/plugins/publishings/infoq-pub/dist/profile-check.js +22 -22
  47. package/plugins/publishings/jike-pub/dist/index.js +22 -22
  48. package/plugins/publishings/jike-pub/dist/profile-check.js +22 -22
  49. package/plugins/publishings/juejin-pub/dist/index.js +22 -22
  50. package/plugins/publishings/juejin-pub/dist/profile-check.js +22 -22
  51. package/plugins/publishings/medium-pub/dist/index.js +9 -9
  52. package/plugins/publishings/podcast-pub/dist/index.js +9 -9
  53. package/plugins/publishings/qiita-pub/dist/index.js +9 -9
  54. package/plugins/publishings/shipinhao-pub/dist/index.js +22 -22
  55. package/plugins/publishings/shipinhao-pub/dist/profile-check.js +22 -22
  56. package/plugins/publishings/sspai-pub/dist/index.js +22 -22
  57. package/plugins/publishings/sspai-pub/dist/profile-check.js +22 -22
  58. package/plugins/publishings/substack-pub/dist/index.js +22 -22
  59. package/plugins/publishings/substack-pub/dist/profile-check.js +22 -22
  60. package/plugins/publishings/surfdash-pub/dist/index.js +39 -12
  61. package/plugins/publishings/surfdash-pub/src/index.ts +33 -6
  62. package/plugins/publishings/surfdash-pub/src/patch.ts +4 -0
  63. package/plugins/publishings/threads-pub/dist/index.js +9 -9
  64. package/plugins/publishings/wechatmp-pub/dist/index.js +22 -22
  65. package/plugins/publishings/wechatmp-pub/dist/profile-check.js +22 -22
  66. package/plugins/publishings/weibo-pub/dist/index.js +22 -22
  67. package/plugins/publishings/weibo-pub/dist/profile-check.js +22 -22
  68. package/plugins/publishings/x-pub/dist/index.js +22 -22
  69. package/plugins/publishings/x-pub/dist/profile-check.js +22 -22
  70. package/plugins/publishings/xhs-pub/dist/index.js +22 -22
  71. package/plugins/publishings/xhs-pub/dist/profile-check.js +22 -22
  72. package/plugins/publishings/xiaoyuzhou-pub/dist/index.js +22 -22
  73. package/plugins/publishings/xiaoyuzhou-pub/dist/profile-check.js +22 -22
  74. package/plugins/publishings/zenn-pub/dist/index.js +9 -9
  75. package/plugins/kk/workflows/feature-verification.yaml +0 -89
@@ -4821,7 +4821,7 @@ var init_zod = __esm(() => {
4821
4821
  init_external();
4822
4822
  });
4823
4823
 
4824
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/errors.js
4824
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/errors.js
4825
4825
  var ErrorCode;
4826
4826
  var init_errors3 = __esm(() => {
4827
4827
  ErrorCode = {
@@ -4832,7 +4832,7 @@ var init_errors3 = __esm(() => {
4832
4832
  };
4833
4833
  });
4834
4834
 
4835
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4835
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4836
4836
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
4837
4837
  var init_api_response = __esm(() => {
4838
4838
  init_errors3();
@@ -4855,13 +4855,13 @@ var init_api_response = __esm(() => {
4855
4855
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
4856
4856
  });
4857
4857
 
4858
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4858
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4859
4859
  var init_cursor = () => {};
4860
4860
 
4861
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4861
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4862
4862
  var init_event_severity = () => {};
4863
4863
 
4864
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/output.js
4864
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/output.js
4865
4865
  function processStream(name) {
4866
4866
  const proc = globalThis.process;
4867
4867
  const stream = proc?.[name];
@@ -4879,7 +4879,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
4879
4879
  }
4880
4880
  var defaultStderrTarget;
4881
4881
 
4882
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/index.js
4882
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/index.js
4883
4883
  var init_dist = __esm(() => {
4884
4884
  init_api_response();
4885
4885
  init_cursor();
@@ -11877,7 +11877,7 @@ var init_dist2 = __esm(() => {
11877
11877
  $visitAsync = visit.visitAsync;
11878
11878
  });
11879
11879
 
11880
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/config.js
11880
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/config.js
11881
11881
  var configSchema;
11882
11882
  var init_config = __esm(() => {
11883
11883
  init_dist2();
@@ -11901,7 +11901,7 @@ var init_config = __esm(() => {
11901
11901
  });
11902
11902
  });
11903
11903
 
11904
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11904
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11905
11905
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
11906
11906
  import { dirname, resolve as resolvePath } from "path";
11907
11907
  function createNodeFileSystem(root, paths) {
@@ -12167,7 +12167,7 @@ html, body {
12167
12167
  <div class="illustration-band">
12168
12168
  ${illustrationSrc ? `<img src="${illustrationSrc}" alt="">` : `<div style="width:100%;height:100%;background:${palette.background};"></div>`}
12169
12169
  </div>
12170
- <div class="text-panel">
12170
+ <div class="text-panel" id="text-panel">
12171
12171
  <div class="headline" data-field="headline" id="headline">${escHtml(input.headline)}</div>
12172
12172
  <div class="points-container">
12173
12173
  ${pointsHtml}
@@ -12179,17 +12179,33 @@ html, body {
12179
12179
  (function () {
12180
12180
  // Step headline font down from start until it fits, never below floor.
12181
12181
  var headline = document.getElementById('headline');
12182
+ var panel = document.getElementById('text-panel');
12182
12183
  var headlineMinPx = ${headlineMinPx};
12183
12184
  var headlineStartPx = ${headlineStartPx};
12184
12185
  var safeWidth = ${safeWidth};
12185
- var panelHeight = ${textPanelHeight - safeArea * 2};
12186
12186
  var size = headlineStartPx;
12187
+ // Measure UNWRAPPED: the headline is white-space:normal + word-break:break-all, so a headline
12188
+ // wider than the safe area wraps instead of overflowing \u2014 scrollWidth then equals the container
12189
+ // width and the width check below never fired, leaving the fit loop at its start size. A 10-char
12190
+ // cover headline (96px x 10 = 960px > 936px safe width) wrapped to two lines, pushed the points
12191
+ // block past the safe bottom, and the composer refused every retry because the remediation only
12192
+ // shortens points (2026-10-19 run: points[1], points[2] overflowed, xhs-render failed, the whole
12193
+ // episode stayed unpublished). nowrap makes scrollWidth the real single-line width, so the loop
12194
+ // shrinks the font until the headline fits on one line.
12195
+ headline.style.whiteSpace = 'nowrap';
12196
+ // The vertical budget is SHARED with the points block: measuring only the headline let a 4-bullet
12197
+ // card overflow by ~30px, and the only remediation rewritable in stderr is a points rewrite \u2014 so
12198
+ // the trailing bullet was dropped on every 4-point card (2026-10-19: cards 02/03 shipped 3 of 4
12199
+ // planned points). The panel's own scrollHeight covers headline + margins + gaps + every point.
12187
12200
  while (size > headlineMinPx) {
12188
12201
  headline.style.fontSize = size + 'px';
12189
- if (headline.scrollWidth <= safeWidth && headline.scrollHeight <= panelHeight) break;
12202
+ if (headline.scrollWidth <= safeWidth && panel.scrollHeight <= panel.clientHeight) break;
12190
12203
  size -= 4;
12191
12204
  }
12192
12205
  headline.style.fontSize = Math.max(size, headlineMinPx) + 'px';
12206
+ // Restore wrapping: at the floor size a genuinely too-long headline still wraps (and the composer
12207
+ // then refuses loudly) instead of overflowing the card horizontally.
12208
+ headline.style.whiteSpace = 'normal';
12193
12209
  })();
12194
12210
  </script>
12195
12211
  </body>
@@ -12573,7 +12589,7 @@ var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx)
12573
12589
  });
12574
12590
  }
12575
12591
  });
12576
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/index.js
12592
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/index.js
12577
12593
  init_file_system_node();
12578
12594
  init_config();
12579
12595
 
@@ -275,7 +275,7 @@ html, body {
275
275
  <div class="illustration-band">
276
276
  ${illustrationSrc ? `<img src="${illustrationSrc}" alt="">` : `<div style="width:100%;height:100%;background:${palette.background};"></div>`}
277
277
  </div>
278
- <div class="text-panel">
278
+ <div class="text-panel" id="text-panel">
279
279
  <div class="headline" data-field="headline" id="headline">${escHtml(input.headline)}</div>
280
280
  <div class="points-container">
281
281
  ${pointsHtml}
@@ -287,17 +287,33 @@ html, body {
287
287
  (function () {
288
288
  // Step headline font down from start until it fits, never below floor.
289
289
  var headline = document.getElementById('headline');
290
+ var panel = document.getElementById('text-panel');
290
291
  var headlineMinPx = ${headlineMinPx};
291
292
  var headlineStartPx = ${headlineStartPx};
292
293
  var safeWidth = ${safeWidth};
293
- var panelHeight = ${textPanelHeight - safeArea * 2};
294
294
  var size = headlineStartPx;
295
+ // Measure UNWRAPPED: the headline is white-space:normal + word-break:break-all, so a headline
296
+ // wider than the safe area wraps instead of overflowing — scrollWidth then equals the container
297
+ // width and the width check below never fired, leaving the fit loop at its start size. A 10-char
298
+ // cover headline (96px x 10 = 960px > 936px safe width) wrapped to two lines, pushed the points
299
+ // block past the safe bottom, and the composer refused every retry because the remediation only
300
+ // shortens points (2026-10-19 run: points[1], points[2] overflowed, xhs-render failed, the whole
301
+ // episode stayed unpublished). nowrap makes scrollWidth the real single-line width, so the loop
302
+ // shrinks the font until the headline fits on one line.
303
+ headline.style.whiteSpace = 'nowrap';
304
+ // The vertical budget is SHARED with the points block: measuring only the headline let a 4-bullet
305
+ // card overflow by ~30px, and the only remediation rewritable in stderr is a points rewrite — so
306
+ // the trailing bullet was dropped on every 4-point card (2026-10-19: cards 02/03 shipped 3 of 4
307
+ // planned points). The panel's own scrollHeight covers headline + margins + gaps + every point.
295
308
  while (size > headlineMinPx) {
296
309
  headline.style.fontSize = size + 'px';
297
- if (headline.scrollWidth <= safeWidth && headline.scrollHeight <= panelHeight) break;
310
+ if (headline.scrollWidth <= safeWidth && panel.scrollHeight <= panel.clientHeight) break;
298
311
  size -= 4;
299
312
  }
300
313
  headline.style.fontSize = Math.max(size, headlineMinPx) + 'px';
314
+ // Restore wrapping: at the floor size a genuinely too-long headline still wraps (and the composer
315
+ // then refuses loudly) instead of overflowing the card horizontally.
316
+ headline.style.whiteSpace = 'normal';
301
317
  })();
302
318
  </script>
303
319
  </body>
@@ -4813,7 +4813,7 @@ var init_zod = __esm(() => {
4813
4813
  init_external();
4814
4814
  });
4815
4815
 
4816
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/errors.js
4816
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/errors.js
4817
4817
  var ErrorCode;
4818
4818
  var init_errors3 = __esm(() => {
4819
4819
  ErrorCode = {
@@ -4824,7 +4824,7 @@ var init_errors3 = __esm(() => {
4824
4824
  };
4825
4825
  });
4826
4826
 
4827
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4827
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4828
4828
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
4829
4829
  var init_api_response = __esm(() => {
4830
4830
  init_errors3();
@@ -4847,13 +4847,13 @@ var init_api_response = __esm(() => {
4847
4847
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
4848
4848
  });
4849
4849
 
4850
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4850
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4851
4851
  var init_cursor = () => {};
4852
4852
 
4853
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4853
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4854
4854
  var init_event_severity = () => {};
4855
4855
 
4856
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/output.js
4856
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/output.js
4857
4857
  function processStream(name) {
4858
4858
  const proc = globalThis.process;
4859
4859
  const stream = proc?.[name];
@@ -4871,7 +4871,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
4871
4871
  }
4872
4872
  var defaultStderrTarget;
4873
4873
 
4874
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/index.js
4874
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/index.js
4875
4875
  var init_dist = __esm(() => {
4876
4876
  init_api_response();
4877
4877
  init_cursor();
@@ -11869,7 +11869,7 @@ var init_dist2 = __esm(() => {
11869
11869
  $visitAsync = visit.visitAsync;
11870
11870
  });
11871
11871
 
11872
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/config.js
11872
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/config.js
11873
11873
  var configSchema;
11874
11874
  var init_config = __esm(() => {
11875
11875
  init_dist2();
@@ -11893,7 +11893,7 @@ var init_config = __esm(() => {
11893
11893
  });
11894
11894
  });
11895
11895
 
11896
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11896
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11897
11897
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
11898
11898
  import { dirname, resolve as resolvePath } from "path";
11899
11899
  function createNodeFileSystem(root, paths) {
@@ -12248,14 +12248,14 @@ var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx)
12248
12248
  });
12249
12249
  }
12250
12250
  });
12251
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/index.js
12251
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/index.js
12252
12252
  init_file_system_node();
12253
12253
  init_config();
12254
12254
 
12255
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/fs.js
12255
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/fs.js
12256
12256
  init_file_system_node();
12257
12257
 
12258
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/path.js
12258
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/path.js
12259
12259
  function normalizeSeparators(path) {
12260
12260
  return path.replaceAll("\\", "/");
12261
12261
  }
@@ -12289,7 +12289,7 @@ function dirnamePath(path) {
12289
12289
  return normalized.slice(0, index);
12290
12290
  }
12291
12291
 
12292
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/fs.js
12292
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/fs.js
12293
12293
  async function ensureDirForFile(path, fs = createNodeFileSystem()) {
12294
12294
  await fs.ensureDir(dirnamePath(path));
12295
12295
  }
@@ -4813,7 +4813,7 @@ var init_zod = __esm(() => {
4813
4813
  init_external();
4814
4814
  });
4815
4815
 
4816
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/errors.js
4816
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/errors.js
4817
4817
  var ErrorCode;
4818
4818
  var init_errors3 = __esm(() => {
4819
4819
  ErrorCode = {
@@ -4824,7 +4824,7 @@ var init_errors3 = __esm(() => {
4824
4824
  };
4825
4825
  });
4826
4826
 
4827
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4827
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/api-response.js
4828
4828
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
4829
4829
  var init_api_response = __esm(() => {
4830
4830
  init_errors3();
@@ -4847,13 +4847,13 @@ var init_api_response = __esm(() => {
4847
4847
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
4848
4848
  });
4849
4849
 
4850
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4850
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/cursor.js
4851
4851
  var init_cursor = () => {};
4852
4852
 
4853
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4853
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
4854
4854
  var init_event_severity = () => {};
4855
4855
 
4856
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/output.js
4856
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/output.js
4857
4857
  function processStream(name) {
4858
4858
  const proc = globalThis.process;
4859
4859
  const stream = proc?.[name];
@@ -4871,7 +4871,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
4871
4871
  }
4872
4872
  var defaultStderrTarget;
4873
4873
 
4874
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/index.js
4874
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/index.js
4875
4875
  var init_dist = __esm(() => {
4876
4876
  init_api_response();
4877
4877
  init_cursor();
@@ -11869,7 +11869,7 @@ var init_dist2 = __esm(() => {
11869
11869
  $visitAsync = visit.visitAsync;
11870
11870
  });
11871
11871
 
11872
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/config.js
11872
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/config.js
11873
11873
  var configSchema;
11874
11874
  var init_config = __esm(() => {
11875
11875
  init_dist2();
@@ -11893,7 +11893,7 @@ var init_config = __esm(() => {
11893
11893
  });
11894
11894
  });
11895
11895
 
11896
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11896
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11897
11897
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
11898
11898
  import { dirname, resolve as resolvePath } from "path";
11899
11899
  function createNodeFileSystem(root, paths) {
@@ -12248,7 +12248,7 @@ var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx)
12248
12248
  });
12249
12249
  }
12250
12250
  });
12251
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/index.js
12251
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/index.js
12252
12252
  init_file_system_node();
12253
12253
  init_config();
12254
12254
 
@@ -79,6 +79,24 @@ that evidence belongs to task 0258.
79
79
  > Grade any render with `scripts/audit-speaker-consistency.py` (needs this plugin's venv):
80
80
  > a per-item F0 spread over 45 Hz means the profile is not anchoring a speaker.
81
81
 
82
+ ### Known artifact: a 40 ms echo lattice on long renders (2026-10-20)
83
+
84
+ A `reference`-anchored profile renders short text clean and long text with a 40 ms (≈25 Hz) periodic
85
+ reflection plus a pause floor only 16–22 dB below speech — heard as 「回声感、瓮声瓮气」. Measured on the
86
+ raw model output (no ffmpeg join, no mp3): `kk stage audio-quality` reports `cepstrum 40 ms @ 27–31 dB`
87
+ for renders >30 s, `pause floor −16…−22 dB`, while a 10 s render of the same profile/text measures
88
+ `22 ms @ 19 dB / −22.5 dB` and the same days' `gemini-tts` episodes measure `20–25 ms @ 19–20 dB /
89
+ −34…−37 dB`. `inference_timesteps`, `cfg_value` and `normalize` do not move it (measured 2026-10-20).
90
+
91
+ ```bash
92
+ # reproducible in ~2.5 min, no episode needed:
93
+ plugins/generations/voxcpm-tts/.venv/bin/python \
94
+ plugins/generations/voxcpm-tts/scripts/probe-long-render.py --out /tmp/voxcpm-probe
95
+ kk stage audio-quality /tmp/voxcpm-probe/long-baseline.wav
96
+ ```
97
+
98
+ Treat a driver/profile change as unproven until a LONG render is measured, not a single sentence.
99
+
82
100
  ## Control policy
83
101
 
84
102
  `normalize` maps directly; an explicit `seed` calls `torch.manual_seed` before synthesis (the
@@ -90,3 +108,16 @@ one for every segment, derived from its `emotion`, and the anchored clip already
90
108
  A per-request `engine`,
91
109
  `personality=true` or an active `effects_chain` is rejected. Speed stays in shared postprocessing.
92
110
  Transcription is omitted, so ASR-dependent QC is reported unavailable (not passing evidence).
111
+
112
+ #### API/library claim sources and confidence
113
+
114
+ The externally changeable claims this file makes about the installed `voxcpm` package, each with the
115
+ artifact it was read from. This block is enforced by `structure/api-library-claim-citation` (the file
116
+ is in that rule's `--require-block` registry), so a HIGH claim without a citation fails the gate.
117
+
118
+ | Claim | Source | Local verification | Confidence |
119
+ | --- | --- | --- | --- |
120
+ | `reference_wav_path` is accepted only by VoxCPM2 checkpoints; any other model id refuses it, so a `reference` profile is VoxCPM2-only while older checkpoints clone through `prompt_wav_path` + `prompt_text` | installed `voxcpm` package | `plugins/generations/voxcpm-tts/.venv/lib/python3.12/site-packages/voxcpm/core.py:239` (`ValueError("reference_wav_path is only supported with VoxCPM2 models")`); reproduced with `scripts/probe-long-render.py --model openbmb/VoxCPM1.5` | HIGH |
121
+ | `generate()`/`_generate()` exposes `cfg_value` (default 2.0), `inference_timesteps` (10), `normalize`, `denoise` and `max_len`, and this plugin passes none of them — the profile and text are the only inputs it sets | installed `voxcpm` package plus this plugin's worker | `…/site-packages/voxcpm/core.py:180`–`:193` (signature and defaults) and `python/worker.py:252`–`:262` (the three `generate(...)` call shapes) | HIGH |
122
+ | `VOXCPM_MODEL` defaults to `openbmb/VoxCPM2`, the model self-reports its output rate, and that rate is what the WAV header carries (no resampling in this plugin) | this plugin's worker | `python/worker.py:181` (`environ.get("VOXCPM_MODEL", "openbmb/VoxCPM2")`), `:207` (`int(model.tts_model.sample_rate)`) and `:264` (`write_pcm16_wav(dest, pcm, sample_rate)`) | HIGH |
123
+ | A `reference` profile pins one speaker (median-pitch swing 22–26 Hz, sd 9–12 Hz) while `instruct` samples a new speaker per request (141 Hz swing), so multi-segment work needs a reference or continuation profile | measured on this machine, 2026-10-15, three texts | `scripts/audit-speaker-consistency.py` grades a render; the 2026-10-15 figures are the ones its docstring records | MEDIUM |
@@ -13,7 +13,7 @@ var __esm = (fn, res, err) => () => {
13
13
  };
14
14
  var __require = import.meta.require;
15
15
 
16
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/errors.js
16
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/errors.js
17
17
  var ErrorCode;
18
18
  var init_errors = __esm(() => {
19
19
  ErrorCode = {
@@ -24,7 +24,7 @@ var init_errors = __esm(() => {
24
24
  };
25
25
  });
26
26
 
27
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/api-response.js
27
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/api-response.js
28
28
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
29
29
  var init_api_response = __esm(() => {
30
30
  init_errors();
@@ -47,13 +47,13 @@ var init_api_response = __esm(() => {
47
47
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
48
48
  });
49
49
 
50
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/cursor.js
50
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/cursor.js
51
51
  var init_cursor = () => {};
52
52
 
53
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
53
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
54
54
  var init_event_severity = () => {};
55
55
 
56
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/output.js
56
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/output.js
57
57
  function processStream(name) {
58
58
  const proc = globalThis.process;
59
59
  const stream = proc?.[name];
@@ -71,7 +71,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
71
71
  }
72
72
  var defaultStderrTarget;
73
73
 
74
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.30/node_modules/@gobing-ai/ts-utils/dist/index.js
74
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.32/node_modules/@gobing-ai/ts-utils/dist/index.js
75
75
  var init_dist = __esm(() => {
76
76
  init_api_response();
77
77
  init_cursor();
@@ -11869,7 +11869,7 @@ var init_dist2 = __esm(() => {
11869
11869
  $visitAsync = visit.visitAsync;
11870
11870
  });
11871
11871
 
11872
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/config.js
11872
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/config.js
11873
11873
  var configSchema;
11874
11874
  var init_config = __esm(() => {
11875
11875
  init_dist2();
@@ -11893,7 +11893,7 @@ var init_config = __esm(() => {
11893
11893
  });
11894
11894
  });
11895
11895
 
11896
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11896
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
11897
11897
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
11898
11898
  import { dirname, resolve as resolvePath } from "path";
11899
11899
  function createNodeFileSystem(root, paths) {
@@ -12251,7 +12251,7 @@ var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx)
12251
12251
  });
12252
12252
  }
12253
12253
  });
12254
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.30+fa3ca66e1fba4d51/node_modules/@gobing-ai/ts-runtime/dist/index.js
12254
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.32+180a6e424da77181/node_modules/@gobing-ai/ts-runtime/dist/index.js
12255
12255
  init_file_system_node();
12256
12256
  init_config();
12257
12257
 
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env python3
2
+ """Reproduce the long-form voxcpm "echo / hollow" artifact in ~2.5 minutes.
3
+
4
+ Why this exists: the 2026-10-20 operator report ("回声感、瓮声瓮气") is not reproducible on a short
5
+ sentence — a 10 s render comes out clean — but it IS reproducible on a paragraph of ~450 Chinese
6
+ characters, which is the length the daily pipeline actually renders per section. Measured 2026-10-20
7
+ with `kk stage audio-quality` (real-cepstrum echo probe + pause floor):
8
+
9
+ short render (~10 s) cepstrum 22 ms @ 19 dB pause floor -22.5 dB clean
10
+ long render (~72 s) cepstrum 40 ms @ 30 dB pause floor -16.1 dB reproduced
11
+ shipped 2026-10-20 §00 cepstrum 40 ms @ 23 dB pause floor -15.7 dB reproduced
12
+
13
+ So the artifact is duration-dependent, and a knob experiment has to use a LONG text or it measures
14
+ nothing. The same run measured `inference_timesteps=20` (29.6 dB) and `cfg_value=2.5` (31.5 dB) against
15
+ the default's 30 dB: none of the exposed sampler knobs remove the 40 ms periodicity.
16
+
17
+ Usage (needs the plugin venv):
18
+
19
+ plugins/generations/voxcpm-tts/.venv/bin/python \
20
+ plugins/generations/voxcpm-tts/scripts/probe-long-render.py [--out /tmp/voxcpm-probe]
21
+
22
+ kk stage audio-quality /tmp/voxcpm-probe/long-baseline.wav # then read cepstrum + pauseFloor
23
+
24
+ Options: `--text-file <path>` (default: the built-in paragraph below), `--ref <wav>` (default: the
25
+ operator's `robin-news` clip), `--steps N`, `--cfg F`, `--normalize`, `--name <label>`.
26
+
27
+ The verdict vocabulary lives in `plugins/kk/scripts/audio-quality.ts` (`kk stage audio-quality`);
28
+ this script only renders.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import argparse
34
+ import contextlib
35
+ import os
36
+ import sys
37
+ import time
38
+ import wave
39
+
40
+ DEFAULT_TEXT = (
41
+ "大家好,今天是2026年10月20日,星期二。这里是由Robin为你带来的咸话咸说之每日AI乱炖。"
42
+ "今天聊两件跟动手有关的事,一位自称几乎不懂游戏开发的作者,靠编程智能体把一款手机端的即时战略游戏"
43
+ "一路做到能离线运行;另一件是 Google 开源了让 PyTorch 跑上 TPU 的项目。两条线索都指向同一件事:"
44
+ "工具链的边界在移动,真正决定成败的不是模型榜单,而是谁能把验收口径写清楚。"
45
+ "先说游戏那条,作者的说法很朴素,他不写引擎,只把需求拆成可以验证的小步,让智能体一步一步改,"
46
+ "每一步都跑一次构建,坏了自己回滚。这种做法听起来笨,但它把不确定性压到了单步之内,"
47
+ "出问题的时候能立刻定位到底层接口还是生成逻辑。我更在意的是这套流程对工程团队的启示:"
48
+ "当生成成本降到几乎为零,稀缺的就不是代码,而是判断哪一步值得交给机器、哪一步必须留给人验。"
49
+ )
50
+ DEFAULT_REF = os.path.expanduser("~/.config/kk/voices/robin-news.wav")
51
+
52
+
53
+ def main() -> int:
54
+ parser = argparse.ArgumentParser(description="Render one long-form voxcpm sample for echo triage.")
55
+ parser.add_argument("--text-file", default=None, help="UTF-8 text to render (default: built-in paragraph)")
56
+ parser.add_argument("--ref", default=DEFAULT_REF, help="reference clip (default: %(default)s)")
57
+ parser.add_argument("--out", default="/tmp/voxcpm-probe", help="output directory (default: %(default)s)")
58
+ parser.add_argument("--name", default="long-baseline", help="output file stem (default: %(default)s)")
59
+ parser.add_argument("--steps", type=int, default=10, help="inference_timesteps (default 10, the plugin's)")
60
+ parser.add_argument("--cfg", type=float, default=2.0, help="cfg_value (default 2.0, the plugin's)")
61
+ parser.add_argument("--normalize", action="store_true", help="pass normalize=True")
62
+ parser.add_argument(
63
+ "--mode",
64
+ choices=["reference", "continuation", "instruct"],
65
+ default="reference",
66
+ help="reference cloning (VoxCPM2 only), prompt continuation, or instruct-only (default reference)",
67
+ )
68
+ parser.add_argument("--prompt-text", default=None, help="transcript of --ref, required by --mode continuation")
69
+ parser.add_argument(
70
+ "--denoise",
71
+ action="store_true",
72
+ help="load the ZipEnhancer denoiser and pass denoise=True (the plugin ships load_denoiser=False)",
73
+ )
74
+ parser.add_argument("--model", default="openbmb/VoxCPM2", help="hub id or local snapshot")
75
+ args = parser.parse_args()
76
+
77
+ text = open(args.text_file, encoding="utf-8").read().strip() if args.text_file else DEFAULT_TEXT
78
+ if not text:
79
+ print("probe: empty text", file=sys.stderr)
80
+ return 2
81
+ if not os.path.isfile(args.ref):
82
+ print(f"probe: reference clip not found: {args.ref}", file=sys.stderr)
83
+ return 2
84
+ os.makedirs(args.out, exist_ok=True)
85
+
86
+ # The model prints its own progress on stdout; keep this script's stdout for the summary.
87
+ with contextlib.redirect_stdout(sys.stderr):
88
+ import numpy as np
89
+ import voxcpm
90
+
91
+ model = voxcpm.VoxCPM.from_pretrained(
92
+ args.model, load_denoiser=args.denoise, optimize=False, device=None
93
+ )
94
+ sample_rate = int(model.tts_model.sample_rate)
95
+
96
+ if args.mode == "continuation" and not args.prompt_text:
97
+ print("probe: --mode continuation needs --prompt-text (the transcript of --ref)", file=sys.stderr)
98
+ return 2
99
+ # Only VoxCPM2 accepts `reference_wav_path`; every other checkpoint clones through a prompt pair.
100
+ anchoring = {
101
+ "reference": {"reference_wav_path": args.ref},
102
+ "continuation": {"prompt_wav_path": args.ref, "prompt_text": args.prompt_text or ""},
103
+ "instruct": {},
104
+ }[args.mode]
105
+
106
+ started = time.time()
107
+ with contextlib.redirect_stdout(sys.stderr):
108
+ waveform = model.generate(
109
+ text=text,
110
+ cfg_value=args.cfg,
111
+ inference_timesteps=args.steps,
112
+ normalize=args.normalize,
113
+ denoise=args.denoise,
114
+ **anchoring,
115
+ )
116
+ samples = np.clip(np.asarray(waveform).squeeze(), -1.0, 1.0)
117
+ path = os.path.join(args.out, f"{args.name}.wav")
118
+ with wave.open(path, "wb") as handle:
119
+ handle.setnchannels(1)
120
+ handle.setsampwidth(2)
121
+ handle.setframerate(sample_rate)
122
+ handle.writeframes((samples * 32767).astype(np.int16).tobytes())
123
+
124
+ seconds = len(samples) / sample_rate
125
+ print(
126
+ f"{path} {seconds:.1f}s sr={sample_rate} chars={len(text)} "
127
+ f"mode={args.mode} steps={args.steps} cfg={args.cfg} normalize={args.normalize} denoise={args.denoise} render={time.time() - started:.1f}s"
128
+ )
129
+ print("measure it with: kk stage audio-quality " + path, file=sys.stderr)
130
+ return 0
131
+
132
+
133
+ if __name__ == "__main__":
134
+ sys.exit(main())