@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"];
@@ -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`.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "kk",
3
- "version": "0.1.0",
3
+ "version": "0.0.14",
4
4
  "description": "knowledge-kit Claude Code plugin: skills, commands, subagents, hooks, and rules"
5
5
  }
@@ -86,8 +86,10 @@ owns the schema-fill rules, the multi-image merge rules, the cap-5 refusal wordi
86
86
  where the preset is written (user root, shadowing by design), and the validation step:
87
87
  read the images with your own vision, write `~/.config/kk/image-presets/styles/<name>.yaml`
88
88
  filling exactly the `StylePreset` fields, then validate with a `KK_IMAGE_DRY_RUN=1` run
89
- whose `style` is the new preset's name. Extraction never writes a `formats/*.yaml` —
90
- a format is not recoverable from a picture.
89
+ whose `style` is the new preset's name. Extraction writes `styles/*.yaml`; with
90
+ `--emit-format <name> --job <job>` it additionally **drafts** a `formats/*.yaml` from
91
+ the same references — a different act with its own authoritative procedure:
92
+ [references/format-drafting.md](references/format-drafting.md).
91
93
 
92
94
  ### list-presets
93
95
 
@@ -109,6 +111,7 @@ output is also the text an unknown `--format`/`--style` refusal quotes.
109
111
  [prompt] [--format <name>] [--style <name>] [--var KEY=VALUE]... [--content <file>]
110
112
  [--ref <path>]... [--count <n>] [--provider <name>] [--model <id>]
111
113
  [--out <dir|file>] [--dry-run] [--list-presets] [--extract-style <name>]
114
+ [--emit-format <name> --job <job>]
112
115
  ```
113
116
 
114
117
  | Token | Meaning | Default |
@@ -126,11 +129,15 @@ output is also the text an unknown `--format`/`--style` refusal quotes.
126
129
  | `--dry-run` | compose and price, generate nothing | off |
127
130
  | `--list-presets` | → the `list-presets` operation | — |
128
131
  | `--extract-style <name>` | → the `extract-style` operation; **requires `--ref`** | — |
132
+ | `--emit-format <name>` | with `--extract-style`: also draft a format preset from the same refs; **requires `--job`** | — |
133
+ | `--job free\|cover\|illustration` | declared job for the drafted format — never inferred from pixels | — |
129
134
 
130
135
  **Validation is this skill's, before any plugin spawn**, each refusal naming the
131
136
  offending argument: unknown `--format` or `--style` (quote what `list-presets` would
132
137
  show); `--count` on a non-`illustration` job; more than five `--ref` paths;
133
- `--extract-style` without `--ref`; a `--content` file that does not exist. Flags the
138
+ `--extract-style` without `--ref`; `--emit-format` without `--extract-style` or
139
+ without `--job`, or a `--job` outside `free|cover|illustration`; a `--content` file
140
+ that does not exist. Flags the
134
141
  wt plugin retired are **answered, not ignored** — state the replacement and stop; the
135
142
  table lives in
136
143
  [references/migrating-from-wt.md](references/migrating-from-wt.md)
@@ -0,0 +1,57 @@
1
+ # Format drafting from reference images
2
+
3
+ Loaded by the image-authoring skill when `extract-style` runs with
4
+ `--emit-format <name> --job <job>`. Produces a **draft** `FormatPreset` from the same
5
+ reference images, for the operator to confirm and fine-tune. This is drafting, not
6
+ extraction: a picture supplies measurements and visual defaults, never job semantics
7
+ or variable contracts — those are **declared** or **reused**, and the report must say
8
+ which is which.
9
+
10
+ ## Field provenance — three tiers, never blurred
11
+
12
+ | Tier | Fields | Source |
13
+ | ---- | ------ | ------ |
14
+ | **Measured** | `aspectRatio`, `width`, `height` | Observed pixel dimensions of the largest reference; `aspectRatio` is the nearest named ratio from `21:9`, `4:3`, `1:1`, `16:9`, `3:4`, `9:16`. No taste involved. |
15
+ | **Declared** | `name`, `job` | The operator's `--emit-format <name>` and `--job <job>`. `job` is never inferred from pixels — a picture does not know whether it is a cover. |
16
+ | **Drafted** | `description`, `keywords`, visual `variables` defaults, `template` | Agent vision over the same references the style came from. Fine-tuning expected. |
17
+ | **Reused** | `defaultStyle`, `outputFilename`, variable names, template grammar | See skeleton rule below. `defaultStyle` is the `--extract-style <name>` of this same run — the pairing is the point of doing both in one pass. |
18
+
19
+ ## The skeleton rule
20
+
21
+ Start from the shipped format of the **same job** —
22
+ `plugins/generations/image-gen/presets/formats/<job>.yaml` — read it first, then:
23
+
24
+ - **Keep** its variable names, `outputFilename` grammar, and template placeholder
25
+ structure. The variable-to-article mapping (`{{title}}`, `{{topics}}`, …) is a
26
+ contract with the skill's `cover`/`illustration` branches; renaming variables
27
+ silently breaks `--content` derivation.
28
+ - **Re-author** the visual defaults from the image analysis: `description`,
29
+ `keywords`, and the default values of the visual variables (`visual_style`,
30
+ `composition`, `color_palette`, `atmosphere`, `mood`, or their skeleton
31
+ equivalents) so the drafted prompt would reproduce the reference look.
32
+ - A `free` job needs no `--content` variables; keep the skeleton minimal.
33
+
34
+ ## Output rules
35
+
36
+ Emit **YAML only**, filling **exactly** the `FormatPreset` fields of
37
+ `plugins/generations/image-gen/src/presets.ts` (`name`, `description`, `job`,
38
+ `aspectRatio`, optional `width`/`height`, `defaultStyle`, `keywords`,
39
+ `outputFilename`, `variables`, `template`) — inventing a field is a defect, same rule
40
+ as style extraction. Multi-image merge follows the style-extraction rule: visual
41
+ defaults reflect traits present in **every** reference; discarded divergent traits are
42
+ named in the report.
43
+
44
+ ## Where the preset goes
45
+
46
+ Write to the **user root**: `~/.config/kk/image-presets/formats/<name>.yaml`, after
47
+ showing the composed YAML and getting confirmation (interactive; the Confirmation
48
+ policy governs). Same-name shipped formats are shadowed whole-file — intended, as
49
+ with styles. No registration step; the 0102 loader scans the roots.
50
+
51
+ ## Validation
52
+
53
+ Before reporting done, run one `KK_IMAGE_DRY_RUN=1` generation whose `format` is the
54
+ new preset's name (and whose `style` is the run's extracted style), then report the
55
+ composed prompt from that run's `Content.body`. The report must list each field's
56
+ tier — measured / declared / drafted / reused — so the operator knows exactly what to
57
+ fine-tune.
@@ -76,15 +76,20 @@ presets and not an average:
76
76
  - `confidence` — capped at `medium` when the set disagrees on any fidelity axis.
77
77
  - `source.refImages` — all N absolute paths, in the order given.
78
78
 
79
- ## What extraction never writes
80
-
81
- **Style only — no format extraction in v1.** A `FormatPreset` carries
82
- `template`, `variables`, `keywords`, `defaultStyle`, `outputFilename` — none of
83
- which is recoverable from a picture. Never write a `formats/*.yaml` file. What
84
- an image *does* yield is arithmetic, not extraction: the extraction report
85
- **states the observed pixel dimensions and the nearest named aspect ratio** of
86
- each reference, chosen from `21:9`, `4:3`, `1:1`, `16:9`, `3:4`, `9:16`, as a
87
- suggestion for which existing format to pair the style with.
79
+ ## What extraction writes
80
+
81
+ **Style by default; format drafting is opt-in.** A `FormatPreset` carries `template`,
82
+ `variables`, `keywords`, `defaultStyle`, `outputFilename` — none of which is
83
+ *recoverable* from a picture, so extraction alone never writes a `formats/*.yaml`.
84
+ What an image *does* yield is arithmetic: the extraction report **states the observed
85
+ pixel dimensions and the nearest named aspect ratio** of each reference, chosen from
86
+ `21:9`, `4:3`, `1:1`, `16:9`, `3:4`, `9:16`.
87
+
88
+ When the operator passes `--emit-format <name> --job <job>` alongside `--extract-style`,
89
+ that arithmetic plus the same visual analysis feeds a **draft** format preset — measured
90
+ fields taken, visual defaults authored, structural fields reused from the shipped
91
+ skeleton, operator fine-tuning expected. That procedure lives in
92
+ [format-drafting.md](format-drafting.md); this file stays style-only.
88
93
 
89
94
  ## Pass-through degradation (visible, never silent)
90
95