@gobing-ai/knowledge-kit 0.0.13 → 0.0.15

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 (125) 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 +118 -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 +16 -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 +161 -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 +305 -0
  48. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/profiles.py +108 -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 +340 -0
  51. package/plugins/generations/omni-voice-gen/uv.lock +3510 -0
  52. package/plugins/generations/omni-voice-gen/voices/robin-news.wav +0 -0
  53. package/plugins/generations/voice-gen/dist/index.js +30 -2
  54. package/plugins/generations/voice-gen/src/index.ts +16 -1
  55. package/plugins/generations/voice-gen/src/voicebox-client.ts +3 -1
  56. package/plugins/ingestions/aihot-ingest/dist/index.js +20 -0
  57. package/plugins/ingestions/horizon-ingest/dist/index.js +20 -0
  58. package/plugins/ingestions/last30days-ingest/dist/index.js +20 -0
  59. package/plugins/ingestions/web-search/dist/index.js +20 -0
  60. package/plugins/kk/commands/image-extract.md +40 -0
  61. package/plugins/kk/commands/image-generate.md +18 -1
  62. package/plugins/kk/commands/workflow-run.md +54 -22
  63. package/plugins/kk/config.example.yaml +5 -0
  64. package/plugins/kk/plugin.json +1 -1
  65. package/plugins/kk/scripts/kk-workflow-stages.ts +1226 -0
  66. package/plugins/kk/{workflows → scripts}/validate-voicescript.ts +4 -4
  67. package/plugins/kk/{workflows → scripts}/wrap-voicescript-doc.ts +7 -6
  68. package/plugins/kk/skills/audio-authoring/SKILL.md +11 -12
  69. package/plugins/kk/skills/image-authoring/SKILL.md +10 -3
  70. package/plugins/kk/skills/image-authoring/references/format-drafting.md +57 -0
  71. package/plugins/kk/skills/image-authoring/references/style-extraction.md +14 -9
  72. package/plugins/kk/skills/itc-generating/SKILL.md +2 -2
  73. package/plugins/kk/skills/itc-generating/references/generic-craft.md +1 -1
  74. package/plugins/kk/skills/itc-generating/references/platform-english.md +1 -1
  75. package/plugins/kk/skills/itc-generating/references/platform-wechat.md +1 -1
  76. package/plugins/kk/skills/storm-research/SKILL.md +5 -5
  77. package/plugins/kk/skills/topic/SKILL.md +7 -7
  78. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +219 -133
  79. package/plugins/kk/workflows/kk-itc.yaml +12 -29
  80. package/plugins/kk/workflows/kk-solo-podcast.yaml +72 -131
  81. package/plugins/kk/workflows/kk-storm-research.yaml +12 -62
  82. package/plugins/publishings/emdash-pub/dist/index.js +20 -0
  83. package/plugins/publishings/podcast-pub/dist/index.js +57 -3
  84. package/plugins/publishings/podcast-pub/src/index.ts +18 -2
  85. package/plugins/publishings/podcast-pub/src/show-notes.ts +56 -9
  86. package/plugins/publishings/qiita-pub/dist/index.js +20 -0
  87. package/plugins/publishings/surfdash-pub/dist/index.js +96 -6
  88. package/plugins/publishings/surfdash-pub/src/index.ts +109 -9
  89. package/plugins/publishings/zenn-pub/dist/index.js +20 -0
  90. package/plugins/sp/scripts/batch-preflight.mjs +346 -0
  91. package/plugins/sp/scripts/batch-preflight.ts +459 -0
  92. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +615 -0
  93. package/plugins/sp/scripts/daily-summary/daily-summary.ts +846 -0
  94. package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
  95. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +223 -0
  96. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +367 -0
  97. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +132 -0
  98. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +169 -0
  99. package/plugins/sp/scripts/feature-dev-precheck.mjs +171 -0
  100. package/plugins/sp/scripts/feature-dev-precheck.ts +238 -0
  101. package/plugins/sp/scripts/feature-sync-bounded.mjs +285 -0
  102. package/plugins/sp/scripts/feature-sync-bounded.ts +478 -0
  103. package/plugins/sp/scripts/history-anatomy-cache.mjs +902 -0
  104. package/plugins/sp/scripts/history-anatomy-cache.ts +1028 -0
  105. package/plugins/sp/scripts/idea-handoff.mjs +22 -0
  106. package/plugins/sp/scripts/idea-handoff.ts +44 -0
  107. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +185 -0
  108. package/plugins/sp/scripts/inline-run-setup.ts +198 -0
  109. package/plugins/sp/scripts/pr-reviewing.mjs +769 -0
  110. package/plugins/sp/scripts/pr-reviewing.ts +925 -0
  111. package/plugins/sp/scripts/quality-gate.mjs +179 -0
  112. package/plugins/sp/scripts/quality-gate.ts +217 -0
  113. package/plugins/sp/scripts/script-contract-check.ts +319 -0
  114. package/plugins/sp/scripts/stage-registry-adapter.ts +1533 -0
  115. package/plugins/sp/scripts/surface-drift-inventory.ts +929 -0
  116. package/plugins/sp/scripts/task-evidence-precheck.ts +181 -0
  117. package/plugins/sp/scripts/task-size-precheck.ts +175 -0
  118. package/plugins/sp/scripts/transition-shim-check.ts +238 -0
  119. package/plugins/sp/scripts/validate-commands.ts +689 -0
  120. package/plugins/sp/scripts/validate-flag-contracts.ts +878 -0
  121. package/plugins/sp/scripts/verify-answer-lint.ts +530 -0
  122. package/plugins/sp/scripts/workflow-step-profile.mjs +316 -0
  123. package/plugins/sp/scripts/workflow-step-profile.ts +456 -0
  124. package/plugins/sp/scripts/wrapup-steps.mjs +373 -0
  125. 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"];
@@ -22268,7 +22288,7 @@ function createVoiceboxClient(options = {}) {
22268
22288
  }
22269
22289
  } catch (err) {
22270
22290
  const reason = err instanceof Error ? err.message : String(err);
22271
- throw new Error(`Voicebox health check failed at ${url2}: ${reason}`);
22291
+ throw new Error(`Voicebox health check failed at ${url2}: ${reason} \u2014 is Voicebox.app running with its REST server enabled? (restart the app or fix VOICEBOX_URL)`);
22272
22292
  }
22273
22293
  },
22274
22294
  async resolveProfile(nameOrId) {
@@ -22810,11 +22830,18 @@ async function processGeneratorIO(inputPath, outputPath, clientOverride, transco
22810
22830
  const scripts = docs.map((doc2) => parseDocToVoiceScript(doc2, envDefaultProfile));
22811
22831
  const combinedScript = mergeVoiceScripts(scripts, docs, envDefaultProfile);
22812
22832
  validateVoiceScript(combinedScript);
22833
+ const renderStartedAt = Date.now();
22834
+ const maxRunMs = process.env.VOICE_GEN_MAX_RUN_MS ? parseInt(process.env.VOICE_GEN_MAX_RUN_MS, 10) : 0;
22835
+ echoError(`voice-gen: ${combinedScript.segments.length} segments queued for local render`);
22813
22836
  const segmentWavs = [];
22814
22837
  const segmentGaps = [];
22815
22838
  const segmentMetadata = [];
22816
22839
  let totalDuration = 0;
22817
- for (const segment of combinedScript.segments) {
22840
+ for (const [segIndex, segment] of combinedScript.segments.entries()) {
22841
+ if (maxRunMs > 0 && Date.now() - renderStartedAt > maxRunMs) {
22842
+ throw new Error(`voice-gen: render budget ${maxRunMs}ms exceeded after ${segIndex}/${combinedScript.segments.length} segments \u2014 Voicebox may be wedged; raise VOICE_GEN_MAX_RUN_MS if the render is legitimately long`);
22843
+ }
22844
+ const segStartedAt = Date.now();
22818
22845
  const speakerConfig = segment.speaker ? combinedScript.speakers?.[segment.speaker] : undefined;
22819
22846
  const profileTarget = segment.profile_id ?? segment.profile ?? speakerConfig?.profile_id ?? speakerConfig?.profile ?? combinedScript.default_profile_id ?? combinedScript.default_profile ?? envDefaultProfile ?? (typeof docs[0]?.metadata?.voiceProfile === "string" ? docs[0].metadata.voiceProfile : undefined);
22820
22847
  if (!profileTarget) {
@@ -22930,6 +22957,7 @@ async function processGeneratorIO(inputPath, outputPath, clientOverride, transco
22930
22957
  transcription,
22931
22958
  loudnessDip
22932
22959
  });
22960
+ echoError(`voice-gen: segment ${segIndex + 1}/${combinedScript.segments.length} done in ${((Date.now() - segStartedAt) / 1000).toFixed(1)}s${verifyRetries ? ` (${verifyRetries} verify ${verifyRetries === 1 ? "retry" : "retries"})` : ""}`);
22933
22961
  }
22934
22962
  const concatenatedWav = concatWavs(segmentWavs, segmentGaps);
22935
22963
  await fs.ensureDir(outDir);
@@ -83,6 +83,12 @@ export async function processGeneratorIO(
83
83
  // 3. Validate VoiceScript
84
84
  validateVoiceScript(combinedScript);
85
85
 
86
+ // Local render can take hours; per-segment progress + an optional total budget keep
87
+ // long renders observable and bounded (dogfood 2026-09-12: healthy 72-min render read as a hang).
88
+ const renderStartedAt = Date.now();
89
+ const maxRunMs = process.env.VOICE_GEN_MAX_RUN_MS ? parseInt(process.env.VOICE_GEN_MAX_RUN_MS, 10) : 0;
90
+ echoError(`voice-gen: ${combinedScript.segments.length} segments queued for local render`);
91
+
86
92
  // 4. Generate each segment
87
93
  const segmentWavs: Uint8Array[] = [];
88
94
  const segmentGaps: number[] = [];
@@ -98,7 +104,13 @@ export async function processGeneratorIO(
98
104
  }> = [];
99
105
  let totalDuration = 0;
100
106
 
101
- for (const segment of combinedScript.segments) {
107
+ for (const [segIndex, segment] of combinedScript.segments.entries()) {
108
+ if (maxRunMs > 0 && Date.now() - renderStartedAt > maxRunMs) {
109
+ throw new Error(
110
+ `voice-gen: render budget ${maxRunMs}ms exceeded after ${segIndex}/${combinedScript.segments.length} segments — Voicebox may be wedged; raise VOICE_GEN_MAX_RUN_MS if the render is legitimately long`,
111
+ );
112
+ }
113
+ const segStartedAt = Date.now();
102
114
  const speakerConfig = segment.speaker ? combinedScript.speakers?.[segment.speaker] : undefined;
103
115
  const profileTarget =
104
116
  segment.profile_id ??
@@ -284,6 +296,9 @@ export async function processGeneratorIO(
284
296
  transcription,
285
297
  loudnessDip,
286
298
  });
299
+ echoError(
300
+ `voice-gen: segment ${segIndex + 1}/${combinedScript.segments.length} done in ${((Date.now() - segStartedAt) / 1000).toFixed(1)}s${verifyRetries ? ` (${verifyRetries} verify ${verifyRetries === 1 ? 'retry' : 'retries'})` : ''}`,
301
+ );
287
302
  }
288
303
 
289
304
  // 5. Concatenate audio
@@ -73,7 +73,9 @@ export function createVoiceboxClient(options: VoiceboxClientOptions = {}): Voice
73
73
  }
74
74
  } catch (err: unknown) {
75
75
  const reason = err instanceof Error ? err.message : String(err);
76
- throw new Error(`Voicebox health check failed at ${url}: ${reason}`);
76
+ throw new Error(
77
+ `Voicebox health check failed at ${url}: ${reason} — is Voicebox.app running with its REST server enabled? (restart the app or fix VOICEBOX_URL)`,
78
+ );
77
79
  }
78
80
  },
79
81
 
@@ -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"];
@@ -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"];
@@ -21850,6 +21850,26 @@ var ResultSchema = exports_external.object({
21850
21850
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21851
21851
  });
21852
21852
  var DocListSchema = exports_external.array(DocSchema);
21853
+ var omniVoiceGenContentSchema = ContentSchema.extend({
21854
+ format: exports_external.literal("audio"),
21855
+ metadata: exports_external.looseObject({
21856
+ generator: exports_external.literal("kk:omni-voice-gen"),
21857
+ audioPath: exports_external.string(),
21858
+ duration: exports_external.number(),
21859
+ segments: exports_external.array(exports_external.looseObject({
21860
+ generationId: exports_external.string(),
21861
+ profile: exports_external.string(),
21862
+ speaker: exports_external.string().optional(),
21863
+ emotion: exports_external.string().optional(),
21864
+ duration: exports_external.number(),
21865
+ verifyRetries: exports_external.number(),
21866
+ transcription: exports_external.string().optional(),
21867
+ loudnessDip: exports_external.boolean().optional()
21868
+ })),
21869
+ mp3Path: exports_external.string().optional(),
21870
+ qc: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21871
+ })
21872
+ });
21853
21873
 
21854
21874
  // ../../packages/kk-core/src/kinds.ts
21855
21875
  var PLUGIN_KINDS = ["ingestion", "generator", "publish"];
@@ -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"];
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: image-extract
3
+ description: Extract a reusable style preset (and optionally draft a format preset) from 1-5 reference images, saved to ~/.config/kk/image-presets/ after confirmation.
4
+ argument-hint: "--name <style-name> --ref <img> [--ref <img>…] [--emit-format <name> --job free|cover|illustration] (max 5 refs)"
5
+ allowed-tools: ["Skill"]
6
+ ---
7
+
8
+ # image-extract
9
+
10
+ Thin wrapper for the `image-authoring` skill's `extract-style` operation — all vision
11
+ analysis, schema-fill, merge, and validation logic lives in the skill. Forward
12
+ `$ARGUMENTS` with one substitution: this command's `--name <style-name>` is the skill's
13
+ `--extract-style <name>` (the flag doubles as the operation selector there — rewrite it,
14
+ do not pass `--name` through). `--ref`, `--emit-format`, and `--job` pass through unchanged.
15
+
16
+ ```text
17
+ Skill(skill="kk:image-authoring", args="$ARGUMENTS with --name rewritten to --extract-style")
18
+ ```
19
+
20
+ ## What it does
21
+
22
+ - Reads 1–5 reference images (`--ref`, repeatable; more than 5 is refused), analyses
23
+ the look, and shows you the composed `StylePreset` YAML for `--name <style-name>`.
24
+ - **Confirms with you before writing**, then saves to the user root
25
+ `~/.config/kk/image-presets/styles/<name>.yaml` — usable immediately via
26
+ `/kk:image-generate --style <name>`, shadowing any shipped preset of the same name.
27
+ - With `--emit-format <name> --job <job>`, additionally **drafts** a format preset from
28
+ the same images: measured dimensions + declared job + visual defaults authored from
29
+ the analysis, skeleton (variables, template grammar) reused from the shipped format
30
+ of the same job. Shown for confirmation and fine-tuning, then written to
31
+ `~/.config/kk/image-presets/formats/<name>.yaml` with `defaultStyle` set to the
32
+ style just extracted.
33
+ - Validates each new preset with a dry-run generation (`KK_IMAGE_DRY_RUN=1`).
34
+
35
+ Examples:
36
+
37
+ ```text
38
+ /kk:image-extract --name flat-retro --ref a.png --ref b.png
39
+ /kk:image-extract --name flat-retro --ref a.png --emit-format retro-cover --job cover
40
+ ```
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: image-generate
3
3
  description: Generate images from a prompt or an article — covers, illustrations, or free-form — using named format and style presets.
4
- argument-hint: "[prompt] [--format <name>] [--style <name>] [--content <file>] [--ref <path>] [--var K=V] [--dry-run] [--list-presets]"
4
+ argument-hint: "[prompt] [--format free|cover|illustration] [--style vibrant|minimalist|photorealistic|technical-diagram|editorial|fresh|warm|cute|sketch|clean-webapp-ui|<custom>] [--content <file>] [--ref <img>…] [--var K=V] [--dry-run] [--list-presets]"
5
5
  allowed-tools: ["Skill"]
6
6
  ---
7
7
 
@@ -13,3 +13,20 @@ confirmation and delegation logic lives in the skill. Forward `$ARGUMENTS` uncha
13
13
  ```text
14
14
  Skill(skill="kk:image-authoring", args="$ARGUMENTS")
15
15
  ```
16
+
17
+ ## Built-in presets (user presets under `~/.config/kk/image-presets/` shadow these)
18
+
19
+ **Formats** (`--format`; default `free`):
20
+
21
+ | Format | Job | Aspect | Default style |
22
+ | ------ | --- | ------ | ------------- |
23
+ | `free` | free-form image from the positional prompt | 1:1 | vibrant |
24
+ | `cover` | article cover; requires `--content <file>` | 21:9 | vibrant |
25
+ | `illustration` | auto-insert illustrations into `--content <file>` | 4:3 | technical-diagram |
26
+
27
+ **Styles** (`--style`): `vibrant` · `minimalist` · `photorealistic` · `technical-diagram` ·
28
+ `editorial` · `fresh` · `warm` · `cute` · `sketch` · `clean-webapp-ui` — or any custom style
29
+ preset name. Omit to use the preference `image.style` or the format's default.
30
+
31
+ Run `--list-presets` for the live list with origins and shadows. Create new presets from
32
+ reference images with `/kk:image-extract`.
@@ -2,8 +2,8 @@
2
2
  name: workflow-run
3
3
  description: >-
4
4
  Run STORM daily research, IT content authoring, or solo-podcast end to end.
5
- Resolves the workflow YAML from the user override, KK_WORKFLOWS_SOURCE, the
6
- installed kk package root, or a repo checkout — runs in place from any cwd;
5
+ Resolves the workflow YAML from the user override, KK_WORKFLOWS_SOURCE, bun/npm
6
+ global installs, the kk package root, or a repo checkout — runs in place from any cwd;
7
7
  creates the config with defaults if missing; computes the workspace; shells
8
8
  spur workflow run against the resolved YAML.
9
9
  argument-hint: "[name] <topic|--in file> [--dir <path>] [--playbook generic|english|wechat] [--research] [--judge] [--outline <a|b|c>] [--writer itc-generating|topic] [--duration <min>] [--language <code>] [--script-approved] [--fixture] [--force]"
@@ -13,8 +13,9 @@ Thin runner around the **storm-research**, **itc-generating** / **topic**, and *
13
13
  capabilities. Read `plugins/kk/skills/storm-research/SKILL.md` or
14
14
  `plugins/kk/skills/itc-generating/SKILL.md` for craft; solo-podcast craft lives in the
15
15
  `audio-authoring` skill. This command owns the run procedure: config create,
16
- workflow YAML resolution (user override → `$KK_WORKFLOWS_SOURCE` → **installed package
17
- root** → repo checkout, runs in place from any cwd), workspace computation, and the
16
+ workflow YAML resolution (user override → `$KK_WORKFLOWS_SOURCE` → **bun/npm global
17
+ install** → **installed package root** → repo checkout, runs in place from any cwd), workspace
18
+ computation, and the
18
19
  `spur workflow run` of the resolved YAML. Design-time SSOT remains
19
20
  `plugins/kk/workflows/` in the package/repo. No new `kk` CLI noun (ADR-011) — everything here
20
21
  is shell + the workflow.
@@ -30,12 +31,13 @@ Parse per the frozen rule:
30
31
  `kk-storm-research` (default), `kk-itc`, `kk-solo-podcast`. Any other name after successful copy → exit 1 listing
31
32
  `kk-storm-research`, `kk-itc`, `kk-solo-podcast`.
32
33
  - `--in <file>` → file mode. `--force` → overwrite an existing dest YAML / existing `brief.md`.
33
- - Profile `kk-storm-research`: `--fixture` → force `fixture: "true"`.
34
- - Profile `kk-itc`: `--dir <path>` (default `./<kebab>`), `--playbook generic|english|wechat` (default `generic`),
34
+ - Profile `kk-storm-research`: `--dir <path>` (default `$works_dir/kk-storm-research/<topic-id>`),
35
+ `--fixture` → force `fixture: "true"`.
36
+ - Profile `kk-itc`: `--dir <path>` (default `$works_dir/kk-itc/<kebab>`), `--playbook generic|english|wechat` (default `generic`),
35
37
  `--research` (`true`|`false`, default `false`), `--judge` (`true`|`false`, default `false`),
36
38
  `--outline <a|b|c>` (default empty), `--writer itc-generating|topic` (default `itc-generating`).
37
39
  `--fixture` passed with `kk-itc` or `kk-solo-podcast` → exit 1 (`fixture is storm-only`).
38
- - Profile `kk-solo-podcast`: `--dir <path>` (default `$works_dir/<kebab>`), `--outline <a|b|c>`
40
+ - Profile `kk-solo-podcast`: `--dir <path>` (default `$works_dir/kk-solo-podcast/<date>`), `--outline <a|b|c>`
39
41
  (default empty), `--duration <min>` (default `8`), `--language <code>` (default `en`),
40
42
  `--script-approved` (sets `script_approved=true`; default off). `--fixture` is storm-only.
41
43
  - **XOR:** exactly one of `<topic>` / `--in <file>`. Both set or both empty → exit 1, stderr
@@ -90,6 +92,19 @@ while [ -L "$kbin" ]; do
90
92
  case "$link" in /*) kbin="$link";; *) kbin="$(dirname "$kbin")/$link";; esac
91
93
  done
92
94
  pkg=""; [ -n "$kbin" ] && pkg="$(cd "$(dirname "$kbin")/.." 2>/dev/null && pwd || true)"
95
+ # Global-install roots — the common no-config case (package installed with `bun install -g`
96
+ # or `npm i -g` and no `workflows_dir` written yet). Each probe is guarded, so a missing
97
+ # package manager never breaks the chain.
98
+ bun_global_workflows=""
99
+ if command -v bun >/dev/null 2>&1; then
100
+ bg="$(dirname "$(bun pm bin -g 2>/dev/null)")/install/global/node_modules/@gobing-ai/knowledge-kit/plugins/kk/workflows"
101
+ [ -d "$bg" ] && bun_global_workflows="$bg"
102
+ fi
103
+ npm_global_workflows=""
104
+ if command -v npm >/dev/null 2>&1; then
105
+ ng="$(dirname "$(npm root -g 2>/dev/null)")/node_modules/@gobing-ai/knowledge-kit/plugins/kk/workflows"
106
+ [ -d "$ng" ] && npm_global_workflows="$ng"
107
+ fi
93
108
  ```
94
109
 
95
110
  Resolution order — first hit wins:
@@ -97,26 +112,31 @@ Resolution order — first hit wins:
97
112
  1. **User override** `$workflows_dir/$NAME.yaml` (default `~/.config/kk/workflows/`) —
98
113
  when it exists it always wins, and nothing is copied.
99
114
  2. `$KK_WORKFLOWS_SOURCE/$NAME.yaml`
100
- 3. `$pkg/plugins/kk/workflows/$NAME.yaml` — the installed package copy
101
- 4. `plugins/kk/workflows/$NAME.yaml` — repo checkout (development)
115
+ 3. **bun global install** — `$(dirname $(bun pm bin -g))/install/global/node_modules/@gobing-ai/knowledge-kit/plugins/kk/workflows/$NAME.yaml`
116
+ 4. **npm global install** — `$(dirname $(npm root -g))/node_modules/@gobing-ai/knowledge-kit/plugins/kk/workflows/$NAME.yaml`
117
+ 5. `$pkg/plugins/kk/workflows/$NAME.yaml` — the installed package copy (resolved from the `kk` binary)
118
+ 6. `plugins/kk/workflows/$NAME.yaml` — repo checkout (development)
119
+
120
+ A corrupt `config.yaml` already exited 1 in step 2; none of these probes runs before that check,
121
+ so no fallback masks a config error.
102
122
 
103
123
  ```bash
104
124
  dest=""
105
125
  if [ -f "$workflows_dir/$NAME.yaml" ]; then
106
126
  dest="$workflows_dir/$NAME.yaml"
107
127
  else
108
- for d in "$KK_WORKFLOWS_SOURCE" ${pkg:+"$pkg/plugins/kk/workflows"} "plugins/kk/workflows"; do
128
+ for d in "$KK_WORKFLOWS_SOURCE" "$bun_global_workflows" "$npm_global_workflows" ${pkg:+"$pkg/plugins/kk/workflows"} "plugins/kk/workflows"; do
109
129
  [ -n "$d" ] && [ -f "$d/$NAME.yaml" ] && { dest="$d/$NAME.yaml"; break; }
110
130
  done
111
- [ -z "$dest" ] && { echo "no source workflow for $NAME (searched $workflows_dir, KK_WORKFLOWS_SOURCE, kk package root, plugins/kk/workflows)" >&2; exit 1; }
131
+ [ -z "$dest" ] && { echo "no source workflow for $NAME (searched $workflows_dir, KK_WORKFLOWS_SOURCE, bun/npm global installs, kk package root, plugins/kk/workflows)" >&2; exit 1; }
112
132
  fi
113
133
  # --force: refresh the user override from the best available source, then run the override.
114
134
  if [ "$FORCE" = true ]; then
115
135
  src=""
116
- for d in "$KK_WORKFLOWS_SOURCE" ${pkg:+"$pkg/plugins/kk/workflows"} "plugins/kk/workflows"; do
136
+ for d in "$KK_WORKFLOWS_SOURCE" "$bun_global_workflows" "$npm_global_workflows" ${pkg:+"$pkg/plugins/kk/workflows"} "plugins/kk/workflows"; do
117
137
  [ -n "$d" ] && [ -f "$d/$NAME.yaml" ] && { src="$d/$NAME.yaml"; break; }
118
138
  done
119
- [ -z "$src" ] && { echo "no source workflow for $NAME to force-install (searched KK_WORKFLOWS_SOURCE, kk package root, plugins/kk/workflows)" >&2; exit 1; }
139
+ [ -z "$src" ] && { echo "no source workflow for $NAME to force-install (searched KK_WORKFLOWS_SOURCE, bun/npm global installs, kk package root, plugins/kk/workflows)" >&2; exit 1; }
120
140
  install -d "$workflows_dir" && cp "$src" "$workflows_dir/$NAME.yaml"
121
141
  dest="$workflows_dir/$NAME.yaml"
122
142
  fi
@@ -126,9 +146,11 @@ fi
126
146
  `--force` to place a fresh copy there) — that override wins on every later run.
127
147
  - No auto-copy, no drift warnings: the package copy is versioned with the CLI and
128
148
  never goes stale; overrides are explicit.
129
- - Sidecars (`validate-voicescript.ts`, `wrap-voicescript-doc.ts`) are **not copied** —
130
- the workflow's own fallback chain resolves them via `$KK_WORKFLOWS_DIR`, the package
131
- root, then `$HOME/.config/kk/workflows`.
149
+ - Sidecars (`plugins/kk/scripts/kk-workflow-stages.ts`, plus the
150
+ `validate-voicescript.ts` / `wrap-voicescript-doc.ts` it delegates to) are **not copied** —
151
+ the workflow resolves the stage runner from the package root, and the runner resolves each
152
+ sidecar via the explicit var, `$KK_WORKFLOWS_DIR`, the package copy, then
153
+ `$HOME/.config/kk/workflows`.
132
154
 
133
155
  ## 4. Compute workspace
134
156
 
@@ -143,7 +165,7 @@ slug=$(printf '%s' "$normalized" | tr -cs 'a-z0-9' '-' | sed 's/^-*//; s/-*$//'
143
165
  [ -z "$slug" ] && slug="topic"
144
166
  hash=$(printf '%s' "$normalized" | shasum -a 256 | cut -c1-8)
145
167
  topic_id="${slug}-${hash}"
146
- work_dir="$works_dir/$topic_id"
168
+ work_dir="${DIR:-$works_dir/kk-storm-research/$topic_id}"
147
169
  ```
148
170
 
149
171
  - `raw` derives empty (no H1 and empty basename) → exit 1 with the derived value.
@@ -157,15 +179,24 @@ mkdir -p "$work_dir"
157
179
 
158
180
  `raw` = `TOPIC` or file-mode first ATX H1 else basename without extension.
159
181
  `kebab` = lower-case, `[^a-z0-9]+` → `-`, trimmed dashes (no length cap, no sha256 hash).
160
- `work_dir="${DIR:-./$kebab}"`. Empty derived `kebab` → exit 1.
182
+ `work_dir="${DIR:-$works_dir/kk-itc/$kebab}"`. Empty derived `kebab` → exit 1. An explicit
183
+ `--dir` still wins, and the default never writes into the caller's cwd.
161
184
 
162
- ### Profile `kk-solo-podcast` / `kk-daily-ai-voice`
185
+ ### Profile `kk-solo-podcast`
163
186
 
164
187
  `date` = today's date in `YYYY-MM-DD` (`$(date +%Y-%m-%d)`).
165
188
  `raw` = `TOPIC` or file-mode first ATX H1 else basename without extension.
166
189
  `kebab` = lower-case, `[^a-z0-9]+` → `-`, trimmed dashes (no length cap, no sha256 hash).
167
190
  `work_dir="${DIR:-$works_dir/kk-solo-podcast/$date}"`.
168
191
 
192
+ ### Profile `kk-daily-ai-voice`
193
+
194
+ Same `date` / `raw` / `kebab` derivation as `kk-solo-podcast`.
195
+ `work_dir="${DIR:-$works_dir/kk-daily-ai-voice/$date}"`.
196
+
197
+ Every profile's default puts its workspace in **its own** `$works_dir/<workflow-name>/` namespace;
198
+ an explicit `--dir` overrides all four defaults.
199
+
169
200
  ## 5. Run the workflow
170
201
 
171
202
  All values are strings.
@@ -216,9 +247,10 @@ spur workflow run "$dest" --vars \
216
247
  and `$work_dir/content.json` (machine contract). Skim `content.md` citations against `docs.json`
217
248
  ids before presenting.
218
249
  - **`kk-itc`**: print resolved `work_dir`, then `$work_dir/brief.md`, `$work_dir/2-outline/outline-approved.md`,
219
- and `$work_dir/3-draft/draft-article.md`. If `judge=true`, also print the verdict path.
220
- - **`kk-solo-podcast`**: print resolved `work_dir`, then `$work_dir/3-script/voicescript.yaml`,
221
- `$work_dir/4-audio/content.json`, and `$work_dir/4-audio/content.wav`.
250
+ and `$work_dir/3-draft-draft-article.md`. If `judge=true`, also print the verdict path.
251
+ - **`kk-solo-podcast`**: print resolved `work_dir`, then `$work_dir/1-briefing-briefing.md`,
252
+ `$work_dir/3-script-voicescript.yaml`, `$work_dir/4-audio/content.json`, and
253
+ `$work_dir/4-audio/content.wav`.
222
254
 
223
255
  If the run ended `failed`, show the failing state (`spur workflow trace <run-id> --json`) and the
224
256
  fail-loud recovery line.
@@ -1,3 +1,8 @@
1
+ # kk operator config. `works_dir` is the run-workspace root — each workflow run defaults
2
+ # to <works_dir>/<workflow-name>/<run-id> unless --dir is given (existing `.works/`-era
3
+ # trees are not migrated). `workflows_dir` is the user-override root for workflow YAMLs;
4
+ # when a workflow is not found there, /workflow-run falls back to KK_WORKFLOWS_SOURCE,
5
+ # bun/npm global installs, the kk package root, then the repo checkout.
1
6
  works_dir: "~/.config/kk/works"
2
7
  workflows_dir: "~/.config/kk/workflows"
3
8
  defaults:
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "kk",
3
- "version": "0.1.0",
3
+ "version": "0.0.15",
4
4
  "description": "knowledge-kit Claude Code plugin: skills, commands, subagents, hooks, and rules"
5
5
  }