@gobing-ai/knowledge-kit 0.0.14 → 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 (26) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/package.json +1 -1
  3. package/plugins/generations/omni-voice-gen/README.md +9 -3
  4. package/plugins/generations/omni-voice-gen/profiles.json +5 -1
  5. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/backend.py +12 -1
  6. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +18 -2
  7. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/profiles.py +8 -0
  8. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/voicescript.py +0 -12
  9. package/plugins/generations/omni-voice-gen/voices/robin-news.wav +0 -0
  10. package/plugins/kk/commands/workflow-run.md +54 -22
  11. package/plugins/kk/config.example.yaml +5 -0
  12. package/plugins/kk/plugin.json +1 -1
  13. package/plugins/kk/scripts/kk-workflow-stages.ts +1226 -0
  14. package/plugins/kk/{workflows → scripts}/validate-voicescript.ts +4 -4
  15. package/plugins/kk/{workflows → scripts}/wrap-voicescript-doc.ts +7 -6
  16. package/plugins/kk/skills/audio-authoring/SKILL.md +11 -12
  17. package/plugins/kk/skills/itc-generating/SKILL.md +2 -2
  18. package/plugins/kk/skills/itc-generating/references/generic-craft.md +1 -1
  19. package/plugins/kk/skills/itc-generating/references/platform-english.md +1 -1
  20. package/plugins/kk/skills/itc-generating/references/platform-wechat.md +1 -1
  21. package/plugins/kk/skills/storm-research/SKILL.md +5 -5
  22. package/plugins/kk/skills/topic/SKILL.md +7 -7
  23. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +149 -163
  24. package/plugins/kk/workflows/kk-itc.yaml +12 -29
  25. package/plugins/kk/workflows/kk-solo-podcast.yaml +72 -131
  26. package/plugins/kk/workflows/kk-storm-research.yaml +12 -62
@@ -29,34 +29,17 @@ vars:
29
29
 
30
30
  states:
31
31
  - id: prepare
32
- description: "mkdir work_dir, 2-outline, 3-draft; validate XOR topic/input_file; write brief.md"
32
+ description: "mkdir work_dir, 2-outline; validate XOR topic/input_file; write brief.md"
33
33
  onEnter:
34
34
  - kind: shell
35
35
  options:
36
36
  command: >-
37
- set -e;
38
- if [ -z "${vars.work_dir}" ]; then
39
- echo "missing work_dir" >&2; exit 1;
40
- fi;
41
- mkdir -p "${vars.work_dir}" "${vars.work_dir}/2-outline" "${vars.work_dir}/3-draft";
42
- echo 0 > "${vars.work_dir}/.revise-count";
43
- if [ -n "${vars.topic}" ] && [ -n "${vars.input_file}" ]; then
44
- echo "XOR violation: both topic and input_file set" >&2; exit 1;
45
- fi;
46
- if [ -z "${vars.topic}" ] && [ -z "${vars.input_file}" ]; then
47
- echo "XOR violation: neither topic nor input_file set" >&2; exit 1;
48
- fi;
49
- if [ -f "${vars.work_dir}/brief.md" ] && [ "${vars.force}" != "true" ]; then
50
- echo "initialization target already exists at ${vars.work_dir}/brief.md; pass force=true to replace" >&2; exit 1;
51
- fi;
52
- if [ -n "${vars.topic}" ]; then
53
- printf '%s\n' "${vars.topic}" > "${vars.work_dir}/brief.md";
54
- else
55
- if [ ! -f "${vars.input_file}" ]; then
56
- echo "input file not found: ${vars.input_file}" >&2; exit 1;
57
- fi;
58
- cp "${vars.input_file}" "${vars.work_dir}/brief.md";
59
- fi;
37
+ kbin="$(command -v kk 2>/dev/null)";
38
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
39
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
40
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
41
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
42
+ bun "$st" prepare-itc "${vars.work_dir}" "${vars.topic}" "${vars.input_file}" "${vars.force}"
60
43
 
61
44
  - id: research
62
45
  description: "Conduct preliminary topic research via storm-research (agent.run)"
@@ -123,9 +106,9 @@ states:
123
106
  agent: ${vars.agent}
124
107
  input: |
125
108
  Invoke the kk:${vars.writer} skill.
126
- Author the technical draft at ${vars.work_dir}/3-draft/draft-article.md based on approved outline ${vars.work_dir}/2-outline/outline-approved.md and brief ${vars.work_dir}/brief.md using playbook ${vars.playbook}.
109
+ Author the technical draft at ${vars.work_dir}/3-draft-draft-article.md based on approved outline ${vars.work_dir}/2-outline/outline-approved.md and brief ${vars.work_dir}/brief.md using playbook ${vars.playbook}.
127
110
  Revision feedback: ${vars.__hitlInput}
128
- expectFile: ${vars.work_dir}/3-draft/draft-article.md
111
+ expectFile: ${vars.work_dir}/3-draft-draft-article.md
129
112
 
130
113
  - id: draft-review
131
114
  description: "Operator reviews and approves or requests revision on draft-article.md"
@@ -133,7 +116,7 @@ states:
133
116
  onEnter:
134
117
  - kind: hitl.confirm
135
118
  options:
136
- prompt: "Review draft at ${vars.work_dir}/3-draft/draft-article.md. Approve?"
119
+ prompt: "Review draft at ${vars.work_dir}/3-draft-draft-article.md. Approve?"
137
120
  var: __hitlAnswer
138
121
 
139
122
  - id: draft-revise
@@ -147,7 +130,7 @@ states:
147
130
  echo $((n + 1)) > "${vars.work_dir}/.revise-count";
148
131
  - kind: hitl.input
149
132
  options:
150
- prompt: "Provide specific revision feedback for ${vars.work_dir}/3-draft/draft-article.md:"
133
+ prompt: "Provide specific revision feedback for ${vars.work_dir}/3-draft-draft-article.md:"
151
134
  var: __hitlInput
152
135
 
153
136
  - id: judge
@@ -159,7 +142,7 @@ states:
159
142
  agent: ${vars.agent}
160
143
  input: |
161
144
  Invoke the kk:content-judge skill.
162
- Evaluate the draft at ${vars.work_dir}/3-draft/draft-article.md against the ${vars.rubric} rubric.
145
+ Evaluate the draft at ${vars.work_dir}/3-draft-draft-article.md against the ${vars.rubric} rubric.
163
146
  Write the verdict JSON to ${vars.work_dir}/.itc-verdict.json per the skill's verdict contract.
164
147
  Print the verdict path as the last line of stdout.
165
148
  expectFile: ${vars.work_dir}/.itc-verdict.json
@@ -37,33 +37,16 @@ states:
37
37
  onEnter:
38
38
  - kind: shell
39
39
  options:
40
- command: >-
41
- set -e;
42
- if [ -z "${vars.work_dir}" ]; then
43
- echo "missing work_dir" >&2; exit 1;
44
- fi;
45
- mkdir -p "${vars.work_dir}" "${vars.work_dir}/1-briefing" "${vars.work_dir}/2-outline" "${vars.work_dir}/3-script" "${vars.work_dir}/4-audio";
46
- if [ -n "${vars.topic}" ] && [ -n "${vars.input_file}" ]; then
47
- echo "XOR violation: both topic and input_file set" >&2; exit 1;
48
- fi;
49
- if [ -z "${vars.topic}" ] && [ -z "${vars.input_file}" ]; then
50
- echo "XOR violation: neither topic nor input_file set" >&2; exit 1;
51
- fi;
52
- if [ -z "${vars.voice_profile}" ] && [ -z "$VOICEBOX_DEFAULT_PROFILE" ]; then
53
- echo "missing voice_profile (set vars.voice_profile or VOICEBOX_DEFAULT_PROFILE)" >&2; exit 1;
54
- fi;
55
- if [ -f "${vars.work_dir}/brief.md" ] && [ "${vars.force}" != "true" ]; then
56
- echo "initialization target already exists at ${vars.work_dir}/brief.md; pass force=true to replace" >&2; exit 1;
57
- fi;
58
- if [ -n "${vars.topic}" ]; then
59
- printf '%s\n' "${vars.topic}" > "${vars.work_dir}/brief.md";
60
- else
61
- if [ ! -f "${vars.input_file}" ]; then
62
- echo "input file not found: ${vars.input_file}" >&2; exit 1;
63
- fi;
64
- cp "${vars.input_file}" "${vars.work_dir}/brief.md";
65
- fi;
66
- echo 0 > "${vars.work_dir}/.revise-count";
40
+ # ADR-115: the XOR / voice_profile / overwrite / brief logic lives in the
41
+ # solo-podcast stage runner; this action only resolves the package root and
42
+ # delegates (one logical call).
43
+ command: >-
44
+ kbin="$(command -v kk 2>/dev/null)";
45
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
46
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
47
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
48
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
49
+ bun "$st" prepare-solo "${vars.work_dir}" "${vars.topic}" "${vars.input_file}" "${vars.voice_profile}" "${vars.force}"
67
50
 
68
51
  - id: understand
69
52
  description: "Analyze brief and generate podcast briefing (agent.run)"
@@ -75,10 +58,10 @@ states:
75
58
  input: |
76
59
  Invoke the kk:audio-authoring skill: operation `briefing`, mode `solo`.
77
60
  Read the source brief at ${vars.work_dir}/brief.md.
78
- Write a concise podcast briefing at ${vars.work_dir}/1-briefing/briefing.md.
61
+ Write a concise podcast briefing at ${vars.work_dir}/1-briefing-briefing.md.
79
62
  Identify core thesis, key listener takeaways, audience profile, target spoken duration (${vars.target_duration_min} minutes), tone, and what material from the brief to emphasize or cut.
80
63
  Flags: --dir ${vars.work_dir} --duration ${vars.target_duration_min}
81
- expectFile: ${vars.work_dir}/1-briefing/briefing.md
64
+ expectFile: ${vars.work_dir}/1-briefing-briefing.md
82
65
 
83
66
  - id: outline-write
84
67
  description: "Generate spoken podcast outline options (agent.run)"
@@ -89,7 +72,7 @@ states:
89
72
  agent: ${vars.agent}
90
73
  input: |
91
74
  Invoke the kk:audio-authoring skill: operation `outline`, mode `solo`.
92
- Read the briefing at ${vars.work_dir}/1-briefing/briefing.md and brief at ${vars.work_dir}/brief.md.
75
+ Read the briefing at ${vars.work_dir}/1-briefing-briefing.md and brief at ${vars.work_dir}/brief.md.
93
76
  Generate spoken podcast outline options in ${vars.work_dir}/2-outline/:
94
77
  - outline-option-a.md (e.g. narrative / storytelling arc)
95
78
  - outline-option-b.md (e.g. analytical / explainer breakdown)
@@ -100,8 +83,8 @@ states:
100
83
  expectFile: ${vars.work_dir}/2-outline/outline-option-a.md
101
84
  - kind: shell
102
85
  options:
103
- command: >-
104
- test -f "${vars.work_dir}/2-outline/outline-option-b.md" || { echo "missing required outline-option-b.md" >&2; exit 1; }
86
+ command: >-
87
+ test -f "${vars.work_dir}/2-outline/outline-option-b.md" || { echo "missing required outline-option-b.md" >&2; exit 1; }
105
88
 
106
89
  - id: outline-select
107
90
  description: "Operator selects preferred outline option"
@@ -121,15 +104,15 @@ states:
121
104
  onEnter:
122
105
  - kind: shell
123
106
  options:
124
- command: >-
125
- sel="${vars.outline}";
126
- if [ -z "$sel" ]; then sel="${vars.__hitlAnswer}"; fi;
127
- if [ -z "$sel" ]; then sel="a"; fi;
128
- src="${vars.work_dir}/2-outline/outline-option-$sel.md";
129
- if [ ! -f "$src" ]; then
130
- echo "selected outline file not found: $src" >&2; exit 1;
131
- fi;
132
- cp "$src" "${vars.work_dir}/2-outline/outline-approved.md";
107
+ command: >-
108
+ sel="${vars.outline}";
109
+ if [ -z "$sel" ]; then sel="${vars.__hitlAnswer}"; fi;
110
+ if [ -z "$sel" ]; then sel="a"; fi;
111
+ src="${vars.work_dir}/2-outline/outline-option-$sel.md";
112
+ if [ ! -f "$src" ]; then
113
+ echo "selected outline file not found: $src" >&2; exit 1;
114
+ fi;
115
+ cp "$src" "${vars.work_dir}/2-outline/outline-approved.md";
133
116
 
134
117
  - id: script-write
135
118
  description: "Author complete VoiceScript YAML from approved outline (agent.run)"
@@ -138,51 +121,32 @@ states:
138
121
  options:
139
122
  role: scribe
140
123
  agent: ${vars.agent}
124
+ # ADR-115 (R3): the VoiceScript field contract is the skill's own
125
+ # templates/voicescript.solo.yaml (task 0081) — not duplicated here. The prompt
126
+ # stays a bounded skill invocation: operation + inputs + output path + budget.
141
127
  input: |
142
128
  Invoke the kk:audio-authoring skill: operation `script`, mode `solo`.
143
- Read the approved outline at ${vars.work_dir}/2-outline/outline-approved.md and briefing at ${vars.work_dir}/1-briefing/briefing.md.
144
- Target duration is ${vars.target_duration_min} minutes.
145
- Spoken budget: if language (${vars.language}) is zh, ja, or ko, target characters = ${vars.target_duration_min} * ${vars.cjk_chars_per_min}; otherwise target words = ${vars.target_duration_min} * ${vars.words_per_min}. Land inside ±20%, spoken prose, one speaker.
146
- Author the complete solo-podcast VoiceScript YAML at ${vars.work_dir}/3-script/voicescript.yaml.
147
- Emit ONLY valid YAML (no markdown fences, no repo/docs paths). Contract:
148
- title: string
149
- language: "${vars.language}"
150
- default_profile: "${vars.voice_profile}"
151
- default_engine: qwen|qwen_custom_voice|luxtts|chatterbox|chatterbox_turbo|tada|kokoro # optional
152
- segments:
153
- - text: "spoken sentence" # required, 1..50000 characters
154
- gap_ms: 400 # optional, >= 0, silence before next clip
155
- instruct: "warm" # optional, <= 500 characters
156
- Do not invent fields. Revision feedback: ${vars.__hitlInput}
157
- Duration retries: if ${vars.work_dir}/.duration-feedback exists, invoke with `--force` (authorized rewrite) and treat its contents as the revision feedback.
158
- Flags: --dir ${vars.work_dir} --duration ${vars.target_duration_min} --language ${vars.language} --profile ${vars.voice_profile} --revise "${vars.__hitlInput}"
159
- expectFile: ${vars.work_dir}/3-script/voicescript.yaml
129
+ Inputs: briefing ${vars.work_dir}/1-briefing-briefing.md; approved outline ${vars.work_dir}/2-outline/outline-approved.md; revision feedback ${vars.__hitlInput}.
130
+ Contract: the skill's templates/voicescript.solo.yaml — `language: "${vars.language}"`, `segments` of spoken text; no `default_profile`, no `title`, no invented fields.
131
+ Budget: ${vars.target_duration_min} min — zh/ja/ko ${vars.cjk_chars_per_min} chars/min, else ${vars.words_per_min} words/min; within ±20%, one speaker.
132
+ Write ONLY the YAML (no fences, no repo paths) to ${vars.work_dir}/3-script-voicescript.yaml.
133
+ Flags: --dir ${vars.work_dir} --duration ${vars.target_duration_min} --language ${vars.language} --profile ${vars.voice_profile} --revise "${vars.__hitlInput}"; add --force when ${vars.work_dir}/.duration-feedback exists (its contents are the revision feedback).
134
+ expectFile: ${vars.work_dir}/3-script-voicescript.yaml
160
135
 
161
136
  - id: script-validate
162
137
  description: "Validate authored VoiceScript YAML structure and constraints"
163
138
  onEnter:
164
139
  - kind: shell
165
140
  options:
166
- command: >-
167
- set -e;
168
- vs="${vars.validate_script}";
169
- if [ ! -f "$vs" ]; then
170
- kbin="$(command -v kk 2>/dev/null || true)";
171
- while [ -L "$kbin" ]; do
172
- link="$(readlink "$kbin")";
173
- case "$link" in /*) kbin="$link";; *) kbin="$(dirname "$kbin")/$link";; esac;
174
- done;
175
- pkg=""; [ -n "$kbin" ] && pkg="$(cd "$(dirname "$kbin")/.." 2>/dev/null && pwd || true)";
176
- vs="";
177
- if [ -n "$KK_WORKFLOWS_DIR" ] && [ -f "$KK_WORKFLOWS_DIR/validate-voicescript.ts" ]; then vs="$KK_WORKFLOWS_DIR/validate-voicescript.ts";
178
- elif [ -n "$pkg" ] && [ -f "$pkg/plugins/kk/workflows/validate-voicescript.ts" ]; then vs="$pkg/plugins/kk/workflows/validate-voicescript.ts";
179
- elif [ -f "$HOME/.config/kk/workflows/validate-voicescript.ts" ]; then vs="$HOME/.config/kk/workflows/validate-voicescript.ts"; fi;
180
- fi;
181
- if [ -z "$vs" ]; then
182
- echo "validate_script not found (searched: \$KK_WORKFLOWS_DIR, kk package root via \`command -v kk\`, \$HOME/.config/kk/workflows) — install the kk package or place an override with /workflow-run kk-solo-podcast --force" >&2;
183
- exit 1;
184
- fi;
185
- bun "$vs" --in "${vars.work_dir}/3-script/voicescript.yaml"
141
+ # ADR-115: package-root resolution + delegation to validate-voicescript.ts
142
+ # (override chain preserved inside the stage runner).
143
+ command: >-
144
+ kbin="$(command -v kk 2>/dev/null)";
145
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
146
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
147
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
148
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
149
+ bun "$st" validate "${vars.validate_script}" --in "${vars.work_dir}/3-script-voicescript.yaml"
186
150
 
187
151
  - id: script-review
188
152
  description: "Operator reviews and approves VoiceScript before live TTS generation"
@@ -190,7 +154,7 @@ states:
190
154
  onEnter:
191
155
  - kind: hitl.confirm
192
156
  options:
193
- prompt: "Review VoiceScript at ${vars.work_dir}/3-script/voicescript.yaml. Approve for voice generation?"
157
+ prompt: "Review VoiceScript at ${vars.work_dir}/3-script-voicescript.yaml. Approve for voice generation?"
194
158
  var: __hitlAnswer
195
159
 
196
160
  - id: script-revise
@@ -199,13 +163,13 @@ states:
199
163
  onEnter:
200
164
  - kind: shell
201
165
  options:
202
- command: >-
203
- rm -f "${vars.work_dir}/.duration-feedback";
204
- n=$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0);
205
- echo $((n + 1)) > "${vars.work_dir}/.revise-count";
166
+ command: >-
167
+ rm -f "${vars.work_dir}/.duration-feedback";
168
+ n=$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0);
169
+ echo $((n + 1)) > "${vars.work_dir}/.revise-count";
206
170
  - kind: hitl.input
207
171
  options:
208
- prompt: "Provide specific revision feedback for ${vars.work_dir}/3-script/voicescript.yaml:"
172
+ prompt: "Provide specific revision feedback for ${vars.work_dir}/3-script-voicescript.yaml:"
209
173
  var: __hitlInput
210
174
 
211
175
  - id: wrap-docs
@@ -213,65 +177,42 @@ states:
213
177
  onEnter:
214
178
  - kind: shell
215
179
  options:
216
- command: >-
217
- set -e;
218
- ws="${vars.wrap_script}";
219
- if [ ! -f "$ws" ]; then
220
- kbin="$(command -v kk 2>/dev/null || true)";
221
- while [ -L "$kbin" ]; do
222
- link="$(readlink "$kbin")";
223
- case "$link" in /*) kbin="$link";; *) kbin="$(dirname "$kbin")/$link";; esac;
224
- done;
225
- pkg=""; [ -n "$kbin" ] && pkg="$(cd "$(dirname "$kbin")/.." 2>/dev/null && pwd || true)";
226
- ws="";
227
- if [ -n "$KK_WORKFLOWS_DIR" ] && [ -f "$KK_WORKFLOWS_DIR/wrap-voicescript-doc.ts" ]; then ws="$KK_WORKFLOWS_DIR/wrap-voicescript-doc.ts";
228
- elif [ -n "$pkg" ] && [ -f "$pkg/plugins/kk/workflows/wrap-voicescript-doc.ts" ]; then ws="$pkg/plugins/kk/workflows/wrap-voicescript-doc.ts";
229
- elif [ -f "$HOME/.config/kk/workflows/wrap-voicescript-doc.ts" ]; then ws="$HOME/.config/kk/workflows/wrap-voicescript-doc.ts"; fi;
230
- fi;
231
- if [ -z "$ws" ]; then
232
- echo "wrap_script not found (searched: \$KK_WORKFLOWS_DIR, kk package root via \`command -v kk\`, \$HOME/.config/kk/workflows) — install the kk package or place an override with /workflow-run kk-solo-podcast --force" >&2;
233
- exit 1;
234
- fi;
235
- bun "$ws" "${vars.work_dir}/3-script/voicescript.yaml" "${vars.work_dir}/4-audio/docs.json" "${vars.voice_profile}"
180
+ # ADR-115: package-root resolution + delegation to wrap-voicescript-doc.ts
181
+ # (override chain preserved inside the stage runner).
182
+ command: >-
183
+ kbin="$(command -v kk 2>/dev/null)";
184
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
185
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
186
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
187
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
188
+ bun "$st" wrap "${vars.wrap_script}" --in "${vars.work_dir}/3-script-voicescript.yaml" --out "${vars.work_dir}/4-audio/docs.json" --profile "${vars.voice_profile}"
236
189
 
237
190
  - id: generate
238
191
  description: "Invoke voice-gen generator plugin to generate audio"
239
192
  onEnter:
240
193
  - kind: shell
241
194
  options:
242
- command: >-
243
- set -e;
244
- extra="";
245
- if [ -n "${vars.plugins_path}" ]; then extra="--plugins-path ${vars.plugins_path}"; fi;
246
- kk executor run voice-gen --in "${vars.work_dir}/4-audio/docs.json" --out "${vars.work_dir}/4-audio/content.json" $extra
195
+ command: >-
196
+ set -e;
197
+ extra="";
198
+ if [ -n "${vars.plugins_path}" ]; then extra="--plugins-path ${vars.plugins_path}"; fi;
199
+ kk executor run voice-gen --in "${vars.work_dir}/4-audio/docs.json" --out "${vars.work_dir}/4-audio/content.json" $extra
247
200
 
248
201
  - id: duration-check
249
202
  description: "Validate generated audio duration against target budget; miss writes .duration-feedback for the retry edge"
250
203
  onEnter:
251
204
  - kind: shell
252
205
  options:
253
- command: >-
254
- rm -f "${vars.work_dir}/4-audio/.duration-ok";
255
- if [ ! -f "${vars.work_dir}/4-audio/content.json" ]; then
256
- exit 0;
257
- fi;
258
- dur=$(jq -r '.metadata.duration // empty' "${vars.work_dir}/4-audio/content.json" 2>/dev/null);
259
- if [ -z "$dur" ]; then
260
- printf 'Regenerate: audio metadata.duration missing or not a number.\n' > "${vars.work_dir}/.duration-feedback";
261
- n=$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0);
262
- echo $((n+1)) > "${vars.work_dir}/.revise-count";
263
- exit 0;
264
- fi;
265
- target_s=$((${vars.target_duration_min} * 60));
266
- min_s=$(awk -v t="$target_s" 'BEGIN {print t * 0.5}');
267
- max_s=$(awk -v t="$target_s" 'BEGIN {print t * 2.0}');
268
- if awk -v d="$dur" -v min="$min_s" -v max="$max_s" 'BEGIN { exit !(d >= min && d <= max) }'; then
269
- touch "${vars.work_dir}/4-audio/.duration-ok";
270
- else
271
- printf 'Regenerate: last audio duration %ss outside 0.5x–2x of %ss; adjust segment lengths toward the target.\n' "$dur" "$target_s" > "${vars.work_dir}/.duration-feedback";
272
- n=$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0);
273
- echo $((n+1)) > "${vars.work_dir}/.revise-count";
274
- fi
206
+ # ADR-115: the band math, .duration-feedback, and .revise-count bump live in
207
+ # the solo-podcast stage runner; the transition guards below still branch on
208
+ # .duration-ok.
209
+ command: >-
210
+ kbin="$(command -v kk 2>/dev/null)";
211
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
212
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
213
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
214
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
215
+ bun "$st" duration "${vars.work_dir}" "${vars.target_duration_min}"
275
216
 
276
217
  - id: done
277
218
  description: "Terminal — Solo podcast VoiceScript and audio generated successfully"
@@ -52,49 +52,12 @@ states:
52
52
  - kind: shell
53
53
  options:
54
54
  command: >-
55
- set -e;
56
- mkdir -p "${vars.work_dir}";
57
- if [ -n "${vars.topic}" ] && [ -n "${vars.input_file}" ]; then
58
- echo "XOR violation: both topic and input_file set" >&2; exit 1;
59
- fi;
60
- if [ -z "${vars.topic}" ] && [ -z "${vars.input_file}" ]; then
61
- echo "XOR violation: neither topic nor input_file set" >&2;
62
- exit 1;
63
- fi;
64
- if [ -n "${vars.topic}" ]; then
65
- jq -n --arg topic "${vars.topic}" --arg maxResults
66
- "${vars.maxResults}" --arg fixture "${vars.fixture}"
67
- '{topic: $topic, maxResults: ($maxResults | tonumber),
68
- fixture: ($fixture == "true")}' > "${vars.work_dir}/topic.json";
69
- exit 0;
70
- fi;
71
- if [ -f "${vars.input_file}" ]; then
72
- cp "${vars.input_file}" "${vars.work_dir}/input.md";
73
- ABS=$(cd "$(dirname "${vars.input_file}")" && pwd)/$(basename
74
- "${vars.input_file}");
75
- QUERY=$(grep -m1 '^# ' "${vars.input_file}" | sed 's/^# *//'
76
- || true);
77
- if [ -z "$QUERY" ]; then
78
- QUERY=$(basename "${vars.input_file}" | sed 's/\.[^.]*$//');
79
- fi;
80
- if [ -z "$QUERY" ]; then
81
- echo "no query derivable (no H1 and empty basename)" >&2;
82
- exit 1;
83
- fi;
84
- ID=$(printf 'file://%s' "$ABS" | shasum -a 256 | cut -c1-16);
85
- jq -n --arg id "$ID" --arg body "$(cat "${vars.input_file}")"
86
- --arg title "$QUERY" --arg sourceUri "file://$ABS" --arg query
87
- "$QUERY" '{id: $id, body: $body, title: $title, sourceUri:
88
- $sourceUri, mediaType: "text/markdown",
89
- metadata: {query: $query, rank: -1, position: 0}}'
90
- > "${vars.work_dir}/local-doc.json";
91
- jq -n --arg topic "$QUERY" --arg maxResults
92
- "${vars.maxResults}" --arg fixture "${vars.fixture}"
93
- '{topic: $topic, maxResults: ($maxResults | tonumber),
94
- fixture: ($fixture == "true")}' > "${vars.work_dir}/topic.json";
95
- else
96
- echo "input_file not readable: ${vars.input_file}" >&2; exit 1;
97
- fi
55
+ kbin="$(command -v kk 2>/dev/null)";
56
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
57
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
58
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
59
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
60
+ bun "$st" prepare-storm "${vars.work_dir}" "${vars.topic}" "${vars.input_file}" "${vars.maxResults}" "${vars.fixture}"
98
61
 
99
62
  - id: ingest
100
63
  description: >-
@@ -139,25 +102,12 @@ states:
139
102
  - kind: shell
140
103
  options:
141
104
  command: >-
142
- set -e;
143
- rs="${vars.render_script}";
144
- if [ ! -f "$rs" ]; then
145
- kbin="$(command -v kk 2>/dev/null || true)";
146
- while [ -L "$kbin" ]; do
147
- link="$(readlink "$kbin")";
148
- case "$link" in /*) kbin="$link";; *) kbin="$(dirname "$kbin")/$link";; esac;
149
- done;
150
- pkg=""; [ -n "$kbin" ] && pkg="$(cd "$(dirname "$kbin")/.." 2>/dev/null && pwd || true)";
151
- rs="";
152
- if [ -n "$pkg" ] && [ -f "$pkg/plugins/kk/scripts/render-md.ts" ]; then rs="$pkg/plugins/kk/scripts/render-md.ts";
153
- elif [ -f "plugins/kk/scripts/render-md.ts" ]; then rs="plugins/kk/scripts/render-md.ts"; fi;
154
- fi;
155
- if [ -z "$rs" ]; then
156
- echo "render_script not found (searched: var, kk package root via \`command -v kk\`, ./plugins/kk/scripts)" >&2;
157
- exit 1;
158
- fi;
159
- bun "$rs" --in "${vars.work_dir}/content.json"
160
- --out "${vars.work_dir}/content.md"
105
+ kbin="$(command -v kk 2>/dev/null)";
106
+ pkg="$(dirname "$(dirname "$(realpath "$kbin" 2>/dev/null)")")";
107
+ st="$pkg/plugins/kk/scripts/kk-workflow-stages.ts";
108
+ [ -f "$st" ] || st="plugins/kk/scripts/kk-workflow-stages.ts";
109
+ [ -f "$st" ] || echo "kk-workflow-stages.ts not found at $st — install or refresh the kk package (bun link in a checkout)" >&2;
110
+ bun "$st" render-storm "${vars.render_script}" --in "${vars.work_dir}/content.json" --out "${vars.work_dir}/content.md"
161
111
 
162
112
  - id: done
163
113
  description: >-