@gobing-ai/knowledge-kit 0.0.13 → 0.0.14

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 (109) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +20 -0
  3. package/package.json +1 -1
  4. package/plugins/generations/content-gen/dist/index.js +20 -0
  5. package/plugins/generations/core-facts-gen/dist/index.js +20 -0
  6. package/plugins/generations/daily-article-gen/dist/index.js +29 -1
  7. package/plugins/generations/daily-article-gen/src/index.ts +13 -1
  8. package/plugins/generations/dailynews-gen/dist/index.js +20 -0
  9. package/plugins/generations/episode-plan-gen/dist/index.js +24 -0
  10. package/plugins/generations/episode-plan-gen/src/index.ts +11 -0
  11. package/plugins/generations/image-gen/dist/index.js +2296 -53
  12. package/plugins/generations/image-gen/src/providers/agnes.ts +110 -0
  13. package/plugins/generations/image-gen/src/providers/azure.ts +153 -0
  14. package/plugins/generations/image-gen/src/providers/codex-cli.ts +170 -0
  15. package/plugins/generations/image-gen/src/providers/dashscope.ts +485 -0
  16. package/plugins/generations/image-gen/src/providers/google.ts +268 -0
  17. package/plugins/generations/image-gen/src/providers/huggingface.ts +59 -0
  18. package/plugins/generations/image-gen/src/providers/jimeng.ts +259 -0
  19. package/plugins/generations/image-gen/src/providers/minimax.ts +171 -0
  20. package/plugins/generations/image-gen/src/providers/openai.ts +319 -0
  21. package/plugins/generations/image-gen/src/providers/openrouter.ts +257 -0
  22. package/plugins/generations/image-gen/src/providers/refs.ts +24 -0
  23. package/plugins/generations/image-gen/src/providers/replicate.ts +279 -0
  24. package/plugins/generations/image-gen/src/providers/seedream.ts +1 -1
  25. package/plugins/generations/image-gen/src/providers/types.ts +52 -51
  26. package/plugins/generations/image-gen/src/providers/zai.ts +237 -0
  27. package/plugins/generations/news-report-gen/dist/index.js +22193 -0
  28. package/plugins/generations/news-report-gen/package.json +17 -0
  29. package/plugins/generations/news-report-gen/plugin.json +7 -0
  30. package/plugins/generations/news-report-gen/src/index.ts +308 -0
  31. package/plugins/generations/news-report-gen/tsconfig.json +4 -0
  32. package/plugins/generations/omni-voice-gen/Makefile +14 -0
  33. package/plugins/generations/omni-voice-gen/README.md +112 -0
  34. package/plugins/generations/omni-voice-gen/bin/omni-voice-gen +2 -0
  35. package/plugins/generations/omni-voice-gen/dist/omni-voice-gen-prr8skpb. +2 -0
  36. package/plugins/generations/omni-voice-gen/dist/omni-voice-gen.js +6 -0
  37. package/plugins/generations/omni-voice-gen/plugin.json +6 -0
  38. package/plugins/generations/omni-voice-gen/profiles.json +12 -0
  39. package/plugins/generations/omni-voice-gen/pyproject.toml +25 -0
  40. package/plugins/generations/omni-voice-gen/scripts/coverage_gate.py +74 -0
  41. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/__init__.py +1 -0
  42. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/__main__.py +39 -0
  43. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/audio.py +190 -0
  44. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/backend.py +150 -0
  45. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/contract.py +76 -0
  46. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/mp3.py +60 -0
  47. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +289 -0
  48. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/profiles.py +100 -0
  49. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/qc.py +234 -0
  50. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/voicescript.py +352 -0
  51. package/plugins/generations/omni-voice-gen/uv.lock +3510 -0
  52. package/plugins/generations/voice-gen/dist/index.js +30 -2
  53. package/plugins/generations/voice-gen/src/index.ts +16 -1
  54. package/plugins/generations/voice-gen/src/voicebox-client.ts +3 -1
  55. package/plugins/ingestions/aihot-ingest/dist/index.js +20 -0
  56. package/plugins/ingestions/horizon-ingest/dist/index.js +20 -0
  57. package/plugins/ingestions/last30days-ingest/dist/index.js +20 -0
  58. package/plugins/ingestions/web-search/dist/index.js +20 -0
  59. package/plugins/kk/commands/image-extract.md +40 -0
  60. package/plugins/kk/commands/image-generate.md +18 -1
  61. package/plugins/kk/plugin.json +1 -1
  62. package/plugins/kk/skills/image-authoring/SKILL.md +10 -3
  63. package/plugins/kk/skills/image-authoring/references/format-drafting.md +57 -0
  64. package/plugins/kk/skills/image-authoring/references/style-extraction.md +14 -9
  65. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +130 -30
  66. package/plugins/publishings/emdash-pub/dist/index.js +20 -0
  67. package/plugins/publishings/podcast-pub/dist/index.js +57 -3
  68. package/plugins/publishings/podcast-pub/src/index.ts +18 -2
  69. package/plugins/publishings/podcast-pub/src/show-notes.ts +56 -9
  70. package/plugins/publishings/qiita-pub/dist/index.js +20 -0
  71. package/plugins/publishings/surfdash-pub/dist/index.js +96 -6
  72. package/plugins/publishings/surfdash-pub/src/index.ts +109 -9
  73. package/plugins/publishings/zenn-pub/dist/index.js +20 -0
  74. package/plugins/sp/scripts/batch-preflight.mjs +346 -0
  75. package/plugins/sp/scripts/batch-preflight.ts +459 -0
  76. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +615 -0
  77. package/plugins/sp/scripts/daily-summary/daily-summary.ts +846 -0
  78. package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
  79. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +223 -0
  80. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +367 -0
  81. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +132 -0
  82. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +169 -0
  83. package/plugins/sp/scripts/feature-dev-precheck.mjs +171 -0
  84. package/plugins/sp/scripts/feature-dev-precheck.ts +238 -0
  85. package/plugins/sp/scripts/feature-sync-bounded.mjs +285 -0
  86. package/plugins/sp/scripts/feature-sync-bounded.ts +478 -0
  87. package/plugins/sp/scripts/history-anatomy-cache.mjs +902 -0
  88. package/plugins/sp/scripts/history-anatomy-cache.ts +1028 -0
  89. package/plugins/sp/scripts/idea-handoff.mjs +22 -0
  90. package/plugins/sp/scripts/idea-handoff.ts +44 -0
  91. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +185 -0
  92. package/plugins/sp/scripts/inline-run-setup.ts +198 -0
  93. package/plugins/sp/scripts/pr-reviewing.mjs +769 -0
  94. package/plugins/sp/scripts/pr-reviewing.ts +925 -0
  95. package/plugins/sp/scripts/quality-gate.mjs +179 -0
  96. package/plugins/sp/scripts/quality-gate.ts +217 -0
  97. package/plugins/sp/scripts/script-contract-check.ts +319 -0
  98. package/plugins/sp/scripts/stage-registry-adapter.ts +1533 -0
  99. package/plugins/sp/scripts/surface-drift-inventory.ts +929 -0
  100. package/plugins/sp/scripts/task-evidence-precheck.ts +181 -0
  101. package/plugins/sp/scripts/task-size-precheck.ts +175 -0
  102. package/plugins/sp/scripts/transition-shim-check.ts +238 -0
  103. package/plugins/sp/scripts/validate-commands.ts +689 -0
  104. package/plugins/sp/scripts/validate-flag-contracts.ts +878 -0
  105. package/plugins/sp/scripts/verify-answer-lint.ts +530 -0
  106. package/plugins/sp/scripts/workflow-step-profile.mjs +316 -0
  107. package/plugins/sp/scripts/workflow-step-profile.ts +456 -0
  108. package/plugins/sp/scripts/wrapup-steps.mjs +373 -0
  109. package/plugins/sp/scripts/wrapup-steps.ts +466 -0
@@ -21848,6 +21848,26 @@ var ResultSchema = exports_external.object({
21848
21848
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21849
21849
  });
21850
21850
  var DocListSchema = exports_external.array(DocSchema);
21851
+ var omniVoiceGenContentSchema = ContentSchema.extend({
21852
+ format: exports_external.literal("audio"),
21853
+ metadata: exports_external.looseObject({
21854
+ generator: exports_external.literal("kk:omni-voice-gen"),
21855
+ audioPath: exports_external.string(),
21856
+ duration: exports_external.number(),
21857
+ segments: exports_external.array(exports_external.looseObject({
21858
+ generationId: exports_external.string(),
21859
+ profile: exports_external.string(),
21860
+ speaker: exports_external.string().optional(),
21861
+ emotion: exports_external.string().optional(),
21862
+ duration: exports_external.number(),
21863
+ verifyRetries: exports_external.number(),
21864
+ transcription: exports_external.string().optional(),
21865
+ loudnessDip: exports_external.boolean().optional()
21866
+ })),
21867
+ mp3Path: exports_external.string().optional(),
21868
+ qc: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21869
+ })
21870
+ });
21851
21871
 
21852
21872
  // ../../packages/kk-core/src/kinds.ts
21853
21873
  var PLUGIN_KINDS = ["ingestion", "generator", "publish"];
@@ -21914,6 +21914,26 @@ var ResultSchema = exports_external.object({
21914
21914
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21915
21915
  });
21916
21916
  var DocListSchema = exports_external.array(DocSchema);
21917
+ var omniVoiceGenContentSchema = ContentSchema.extend({
21918
+ format: exports_external.literal("audio"),
21919
+ metadata: exports_external.looseObject({
21920
+ generator: exports_external.literal("kk:omni-voice-gen"),
21921
+ audioPath: exports_external.string(),
21922
+ duration: exports_external.number(),
21923
+ segments: exports_external.array(exports_external.looseObject({
21924
+ generationId: exports_external.string(),
21925
+ profile: exports_external.string(),
21926
+ speaker: exports_external.string().optional(),
21927
+ emotion: exports_external.string().optional(),
21928
+ duration: exports_external.number(),
21929
+ verifyRetries: exports_external.number(),
21930
+ transcription: exports_external.string().optional(),
21931
+ loudnessDip: exports_external.boolean().optional()
21932
+ })),
21933
+ mp3Path: exports_external.string().optional(),
21934
+ qc: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21935
+ })
21936
+ });
21917
21937
 
21918
21938
  // ../../packages/kk-core/src/kinds.ts
21919
21939
  var PLUGIN_KINDS = ["ingestion", "generator", "publish"];
@@ -22043,7 +22063,59 @@ async function spawnCli(cmd, cwd) {
22043
22063
  return { exitCode, stdout, stderr };
22044
22064
  }
22045
22065
  function cliErrorText(spawned) {
22046
- return spawned.stderr.trim() || spawned.stdout.trim() || "Unknown error";
22066
+ return [spawned.stderr.trim(), spawned.stdout.trim()].filter((part) => part !== "").join(`
22067
+ `) || "Unknown error";
22068
+ }
22069
+ function withEmdashTokenHint(errText) {
22070
+ return /INVALID_TOKEN|API error 401/.test(errText) ? `${errText} \u2014 hint: regenerate the EmDash token (surfing.salty.vip admin console) and update EMDASH_API_TOKEN in ~/.config/kk/config.yaml` : errText;
22071
+ }
22072
+ async function pushPostGit(surfdashRoot, relPostDir, message) {
22073
+ const branch = await spawnCli(["git", "rev-parse", "--abbrev-ref", "HEAD"], surfdashRoot);
22074
+ if (branch.exitCode !== 0)
22075
+ return { ok: false, error: `surfdash git branch check failed: ${cliErrorText(branch)}` };
22076
+ const branchName = branch.stdout.trim();
22077
+ if (branchName !== "main") {
22078
+ return {
22079
+ ok: false,
22080
+ error: `surfdash checkout is on '${branchName}', not 'main' \u2014 deploy.yml only builds main; refusing to push from a feature branch`
22081
+ };
22082
+ }
22083
+ const add = await spawnCli(["git", "add", "--", relPostDir], surfdashRoot);
22084
+ if (add.exitCode !== 0)
22085
+ return { ok: false, error: `surfdash git add failed: ${cliErrorText(add)}` };
22086
+ const staged = await spawnCli(["git", "diff", "--cached", "--quiet", "--", relPostDir], surfdashRoot);
22087
+ if (staged.exitCode === 0) {
22088
+ const unpushed = await spawnCli(["git", "diff", "--quiet", "origin/main..HEAD", "--", relPostDir], surfdashRoot);
22089
+ if (unpushed.exitCode === 0) {
22090
+ const hash3 = await spawnCli(["git", "rev-parse", "--short", "HEAD"], surfdashRoot);
22091
+ return { ok: true, hash: hash3.stdout.trim() || "unknown" };
22092
+ }
22093
+ } else {
22094
+ const commit = await spawnCli(["git", "commit", "-m", message, "--", relPostDir], surfdashRoot);
22095
+ if (commit.exitCode !== 0)
22096
+ return { ok: false, error: `surfdash git commit failed: ${cliErrorText(commit)}` };
22097
+ }
22098
+ const push = await spawnCli(["git", "push", "origin", "main"], surfdashRoot);
22099
+ if (push.exitCode !== 0) {
22100
+ return {
22101
+ ok: false,
22102
+ error: `surfdash git push failed (deploy.yml deploys on push to main): ${cliErrorText(push)}`
22103
+ };
22104
+ }
22105
+ const hash2 = await spawnCli(["git", "rev-parse", "--short", "HEAD"], surfdashRoot);
22106
+ return { ok: true, hash: hash2.stdout.trim() || "unknown" };
22107
+ }
22108
+ async function awaitArticleLive(url2, timeoutMs = 180000, intervalMs = 1e4) {
22109
+ const deadline = Date.now() + timeoutMs;
22110
+ while (Date.now() < deadline) {
22111
+ try {
22112
+ const resp = await fetch(url2, { redirect: "follow", signal: AbortSignal.timeout(5000) });
22113
+ if (resp.ok)
22114
+ return true;
22115
+ } catch {}
22116
+ await Bun.sleep(intervalMs);
22117
+ }
22118
+ return false;
22047
22119
  }
22048
22120
  async function scaffoldLocale(options) {
22049
22121
  const postPath = resolvePostPath(options);
@@ -22102,7 +22174,7 @@ async function syncPost(options) {
22102
22174
  try {
22103
22175
  const spawned = await spawnCli(["bun", "scripts/publish-orchestrator.ts", "sync", postPath.postPath], surfdashRoot);
22104
22176
  if (spawned.exitCode !== 0) {
22105
- return fail(`publish-orchestrator sync failed (exit ${spawned.exitCode}): ${cliErrorText(spawned)}`);
22177
+ return fail(`publish-orchestrator sync failed (exit ${spawned.exitCode}): ${withEmdashTokenHint(cliErrorText(spawned))}`);
22106
22178
  }
22107
22179
  return ResultSchema.parse({
22108
22180
  ok: true,
@@ -22146,14 +22218,29 @@ async function publishPost(payload) {
22146
22218
  await createNodeFileSystem().writeFile(filePath, markdown);
22147
22219
  const spawned = await spawnCli([postsurfingBin, "publish", filePath], surfdashRoot);
22148
22220
  if (spawned.exitCode !== 0) {
22149
- return fail(`postsurfing CLI failed (exit ${spawned.exitCode}): ${cliErrorText(spawned)}`);
22221
+ return fail(`postsurfing CLI failed (exit ${spawned.exitCode}): ${withEmdashTokenHint(cliErrorText(spawned))}`);
22222
+ }
22223
+ const articleUrl = `${(process.env.SURFDASH_URL ?? "https://surfing.salty.vip").replace(/\/$/, "")}/${locale}/posts/${slug}`;
22224
+ if (process.env.SURFDASH_AUTO_PUSH === "0") {
22225
+ return ResultSchema.parse({
22226
+ ok: true,
22227
+ target: TARGET,
22228
+ url: articleUrl,
22229
+ message: "Published via postsurfing CLI (auto-push disabled)",
22230
+ metadata: { postPath: filePath }
22231
+ });
22150
22232
  }
22233
+ const relPostDir = join("content", "posts", "articles", locale, slug);
22234
+ const pushed = await pushPostGit(surfdashRoot, relPostDir, `content: daily AI news ${dateStamp} (zh)`);
22235
+ if (!pushed.ok)
22236
+ return fail(pushed.error);
22237
+ const live = await awaitArticleLive(articleUrl);
22151
22238
  return ResultSchema.parse({
22152
22239
  ok: true,
22153
22240
  target: TARGET,
22154
- url: `https://surfdash.local/${locale}/posts/${slug}`,
22155
- message: "Published successfully to Surfdash via postsurfing CLI",
22156
- metadata: { postPath: filePath }
22241
+ url: articleUrl,
22242
+ message: live ? "Published, committed, pushed, and live on the site" : "Published and pushed; URL not live within the verify window \u2014 check the surfdash deploy workflow",
22243
+ metadata: { postPath: filePath, gitCommit: pushed.hash, live }
22157
22244
  });
22158
22245
  } catch (err) {
22159
22246
  return fail(`Postsurfing transport error: ${err instanceof Error ? err.message : String(err)}`);
@@ -22224,10 +22311,13 @@ if (import.meta.main) {
22224
22311
  process.exit(await main2());
22225
22312
  }
22226
22313
  export {
22314
+ withEmdashTokenHint,
22227
22315
  slugify2 as slugify,
22316
+ pushPostGit,
22228
22317
  processPublishIO,
22229
22318
  mapContentToSurfingMarkdown,
22230
22319
  main2 as main,
22231
22320
  getPublishTransport,
22321
+ awaitArticleLive,
22232
22322
  PostsurfingFileCliTransport
22233
22323
  };
@@ -210,9 +210,85 @@ async function spawnCli(cmd: string[], cwd: string): Promise<CliSpawnResult> {
210
210
  return { exitCode, stdout, stderr };
211
211
  }
212
212
 
213
- /** Stderr-first error text for a failed CLI spawn (stderr may be empty → fall back to stdout). */
213
+ /** Error text for a failed CLI spawn — both streams concatenated: postsurfing streams the
214
+ * failing stage's API error (e.g. 401 INVALID_TOKEN) on stdout while bun stacks land on stderr. */
214
215
  function cliErrorText(spawned: CliSpawnResult): string {
215
- return spawned.stderr.trim() || spawned.stdout.trim() || 'Unknown error';
216
+ return [spawned.stderr.trim(), spawned.stdout.trim()].filter((part) => part !== '').join('\n') || 'Unknown error';
217
+ }
218
+
219
+ /** The EmDash CMS token in kk config expires periodically; map the API's 401 to the fix. */
220
+ export function withEmdashTokenHint(errText: string): string {
221
+ return /INVALID_TOKEN|API error 401/.test(errText)
222
+ ? `${errText} — hint: regenerate the EmDash token (surfing.salty.vip admin console) and update EMDASH_API_TOKEN in ~/.config/kk/config.yaml`
223
+ : errText;
224
+ }
225
+
226
+ /** Outcome of {@link pushPostGit} — the union keeps fail-loud errors typed at the call site. */
227
+ export type GitPushOutcome = { ok: true; hash: string } | { ok: false; error: string };
228
+
229
+ /**
230
+ * Commits the published post path and pushes to the remote. Production deploys run
231
+ * from surfdash's `deploy.yml` on every push to `main` — the publishing FSM itself
232
+ * never touches git, so without this step the article 404s until a manual commit.
233
+ * Committing with a pathspec (`git commit -- <path>`) keeps unrelated staged files
234
+ * out of the publish commit. Fails loud on branch/commit/push errors.
235
+ */
236
+ export async function pushPostGit(surfdashRoot: string, relPostDir: string, message: string): Promise<GitPushOutcome> {
237
+ const branch = await spawnCli(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], surfdashRoot);
238
+ if (branch.exitCode !== 0) return { ok: false, error: `surfdash git branch check failed: ${cliErrorText(branch)}` };
239
+ const branchName = branch.stdout.trim();
240
+ if (branchName !== 'main') {
241
+ return {
242
+ ok: false,
243
+ error: `surfdash checkout is on '${branchName}', not 'main' — deploy.yml only builds main; refusing to push from a feature branch`,
244
+ };
245
+ }
246
+ const add = await spawnCli(['git', 'add', '--', relPostDir], surfdashRoot);
247
+ if (add.exitCode !== 0) return { ok: false, error: `surfdash git add failed: ${cliErrorText(add)}` };
248
+ // Idempotent retry: post content identical to HEAD stages nothing. Only push when
249
+ // origin lacks commits touching this post; a clean post means it's already live.
250
+ const staged = await spawnCli(['git', 'diff', '--cached', '--quiet', '--', relPostDir], surfdashRoot);
251
+ if (staged.exitCode === 0) {
252
+ const unpushed = await spawnCli(
253
+ ['git', 'diff', '--quiet', 'origin/main..HEAD', '--', relPostDir],
254
+ surfdashRoot,
255
+ );
256
+ if (unpushed.exitCode === 0) {
257
+ const hash = await spawnCli(['git', 'rev-parse', '--short', 'HEAD'], surfdashRoot);
258
+ return { ok: true, hash: hash.stdout.trim() || 'unknown' };
259
+ }
260
+ } else {
261
+ const commit = await spawnCli(['git', 'commit', '-m', message, '--', relPostDir], surfdashRoot);
262
+ if (commit.exitCode !== 0) return { ok: false, error: `surfdash git commit failed: ${cliErrorText(commit)}` };
263
+ }
264
+ const push = await spawnCli(['git', 'push', 'origin', 'main'], surfdashRoot);
265
+ if (push.exitCode !== 0) {
266
+ return {
267
+ ok: false,
268
+ error: `surfdash git push failed (deploy.yml deploys on push to main): ${cliErrorText(push)}`,
269
+ };
270
+ }
271
+ const hash = await spawnCli(['git', 'rev-parse', '--short', 'HEAD'], surfdashRoot);
272
+ return { ok: true, hash: hash.stdout.trim() || 'unknown' };
273
+ }
274
+
275
+ /**
276
+ * Polls the article URL until the CDN serves it (deploy.yml build latency). Push
277
+ * acceptance is the authoritative publish signal, so an unverified URL is reported
278
+ * in the result message rather than failing the publish.
279
+ */
280
+ export async function awaitArticleLive(url: string, timeoutMs = 180_000, intervalMs = 10_000): Promise<boolean> {
281
+ const deadline = Date.now() + timeoutMs;
282
+ while (Date.now() < deadline) {
283
+ try {
284
+ const resp = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(5_000) });
285
+ if (resp.ok) return true;
286
+ } catch {
287
+ // network blips during CI deploy — keep polling until the deadline
288
+ }
289
+ await Bun.sleep(intervalMs);
290
+ }
291
+ return false;
216
292
  }
217
293
 
218
294
  /**
@@ -291,7 +367,9 @@ async function syncPost(options: SurfdashPubOptions): Promise<Result> {
291
367
  surfdashRoot,
292
368
  );
293
369
  if (spawned.exitCode !== 0) {
294
- return fail(`publish-orchestrator sync failed (exit ${spawned.exitCode}): ${cliErrorText(spawned)}`);
370
+ return fail(
371
+ `publish-orchestrator sync failed (exit ${spawned.exitCode}): ${withEmdashTokenHint(cliErrorText(spawned))}`,
372
+ );
295
373
  }
296
374
  return ResultSchema.parse({
297
375
  ok: true,
@@ -352,17 +430,39 @@ async function publishPost(payload: PublishTransportPayload): Promise<Result> {
352
430
  const spawned = await spawnCli([postsurfingBin, 'publish', filePath], surfdashRoot);
353
431
 
354
432
  if (spawned.exitCode !== 0) {
355
- return fail(`postsurfing CLI failed (exit ${spawned.exitCode}): ${cliErrorText(spawned)}`);
433
+ return fail(
434
+ `postsurfing CLI failed (exit ${spawned.exitCode}): ${withEmdashTokenHint(cliErrorText(spawned))}`,
435
+ );
436
+ }
437
+
438
+ // Deploy seam: commit + push the post so deploy.yml builds it, then wait for
439
+ // the live URL — downstream show-notes advertise a real page, not a 404.
440
+ // Tests (and offline runs) opt out via SURFDASH_AUTO_PUSH=0.
441
+ const articleUrl = `${(process.env.SURFDASH_URL ?? 'https://surfing.salty.vip').replace(/\/$/, '')}/${locale}/posts/${slug}`;
442
+ if (process.env.SURFDASH_AUTO_PUSH === '0') {
443
+ return ResultSchema.parse({
444
+ ok: true,
445
+ target: TARGET,
446
+ url: articleUrl,
447
+ message: 'Published via postsurfing CLI (auto-push disabled)',
448
+ // Absolute post path lets downstream steps (locale translation + CMS sync)
449
+ // derive the surfdash checkout root without extra configuration.
450
+ metadata: { postPath: filePath },
451
+ });
356
452
  }
453
+ const relPostDir = join('content', 'posts', 'articles', locale, slug);
454
+ const pushed = await pushPostGit(surfdashRoot, relPostDir, `content: daily AI news ${dateStamp} (zh)`);
455
+ if (!pushed.ok) return fail(pushed.error);
456
+ const live = await awaitArticleLive(articleUrl);
357
457
 
358
458
  return ResultSchema.parse({
359
459
  ok: true,
360
460
  target: TARGET,
361
- url: `https://surfdash.local/${locale}/posts/${slug}`,
362
- message: 'Published successfully to Surfdash via postsurfing CLI',
363
- // Absolute post path lets downstream steps (locale translation + CMS sync)
364
- // derive the surfdash checkout root without extra configuration.
365
- metadata: { postPath: filePath },
461
+ url: articleUrl,
462
+ message: live
463
+ ? 'Published, committed, pushed, and live on the site'
464
+ : 'Published and pushed; URL not live within the verify window — check the surfdash deploy workflow',
465
+ metadata: { postPath: filePath, gitCommit: pushed.hash, live },
366
466
  });
367
467
  } catch (err: unknown) {
368
468
  return fail(`Postsurfing transport error: ${err instanceof Error ? err.message : String(err)}`);
@@ -21849,6 +21849,26 @@ var ResultSchema = exports_external.object({
21849
21849
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21850
21850
  });
21851
21851
  var DocListSchema = exports_external.array(DocSchema);
21852
+ var omniVoiceGenContentSchema = ContentSchema.extend({
21853
+ format: exports_external.literal("audio"),
21854
+ metadata: exports_external.looseObject({
21855
+ generator: exports_external.literal("kk:omni-voice-gen"),
21856
+ audioPath: exports_external.string(),
21857
+ duration: exports_external.number(),
21858
+ segments: exports_external.array(exports_external.looseObject({
21859
+ generationId: exports_external.string(),
21860
+ profile: exports_external.string(),
21861
+ speaker: exports_external.string().optional(),
21862
+ emotion: exports_external.string().optional(),
21863
+ duration: exports_external.number(),
21864
+ verifyRetries: exports_external.number(),
21865
+ transcription: exports_external.string().optional(),
21866
+ loudnessDip: exports_external.boolean().optional()
21867
+ })),
21868
+ mp3Path: exports_external.string().optional(),
21869
+ qc: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21870
+ })
21871
+ });
21852
21872
 
21853
21873
  // ../../packages/kk-core/src/kinds.ts
21854
21874
  var PLUGIN_KINDS = ["ingestion", "generator", "publish"];