@gobing-ai/knowledge-kit 0.0.19 → 0.0.22

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 (69) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +161 -142
  3. package/package.json +1 -1
  4. package/plugins/generations/content-gen/dist/index.js +20 -3
  5. package/plugins/generations/core-facts-gen/dist/index.js +20 -3
  6. package/plugins/generations/daily-article-gen/dist/index.js +20 -3
  7. package/plugins/generations/dailynews-gen/dist/index.js +29 -4
  8. package/plugins/generations/dailynews-gen/src/script-builder.ts +19 -1
  9. package/plugins/generations/episode-plan-gen/dist/index.js +20 -3
  10. package/plugins/generations/image-gen/dist/index.js +147 -69
  11. package/plugins/generations/image-gen/src/presets.ts +2 -2
  12. package/plugins/generations/image-gen/src/providers/agnes.ts +6 -2
  13. package/plugins/generations/image-gen/src/providers/azure.ts +6 -2
  14. package/plugins/generations/image-gen/src/providers/dashscope.ts +10 -3
  15. package/plugins/generations/image-gen/src/providers/google.ts +70 -29
  16. package/plugins/generations/image-gen/src/providers/huggingface.ts +3 -0
  17. package/plugins/generations/image-gen/src/providers/jimeng.ts +9 -2
  18. package/plugins/generations/image-gen/src/providers/minimax.ts +10 -2
  19. package/plugins/generations/image-gen/src/providers/openai.ts +9 -3
  20. package/plugins/generations/image-gen/src/providers/openrouter.ts +16 -4
  21. package/plugins/generations/image-gen/src/providers/replicate.ts +13 -3
  22. package/plugins/generations/image-gen/src/providers/seedream.ts +4 -1
  23. package/plugins/generations/image-gen/src/providers/timeouts.ts +14 -0
  24. package/plugins/generations/image-gen/src/providers/types.ts +10 -0
  25. package/plugins/generations/image-gen/src/providers/zai.ts +4 -1
  26. package/plugins/generations/news-report-gen/dist/index.js +20 -3
  27. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +13 -5
  28. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/qc.py +23 -15
  29. package/plugins/generations/voice-gen/dist/index.js +36 -10
  30. package/plugins/generations/voice-gen/src/voicebox-client.ts +18 -4
  31. package/plugins/generations/voice-gen/src/voicebox-server.ts +2 -1
  32. package/plugins/ingestions/aihot-ingest/dist/index.js +26 -6
  33. package/plugins/ingestions/aihot-ingest/plugin.json +1 -1
  34. package/plugins/ingestions/aihot-ingest/src/client.ts +5 -0
  35. package/plugins/ingestions/aihot-ingest/src/rss.ts +12 -2
  36. package/plugins/ingestions/horizon-ingest/dist/index.js +20 -3
  37. package/plugins/ingestions/last30days-ingest/dist/index.js +20 -3
  38. package/plugins/ingestions/web-search/dist/index.js +22 -3
  39. package/plugins/ingestions/web-search/src/index.ts +4 -0
  40. package/plugins/kk/commands/workflow-run.md +20 -6
  41. package/plugins/kk/plugin.json +1 -1
  42. package/plugins/kk/scripts/itc-stages.ts +563 -0
  43. package/plugins/kk/scripts/kk-workflow-stages.ts +125 -18
  44. package/plugins/kk/scripts/render-md.ts +7 -1
  45. package/plugins/kk/skills/article-adapt/SKILL.md +85 -0
  46. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +26 -16
  47. package/plugins/kk/workflows/kk-itc.yaml +461 -12
  48. package/plugins/publishings/emdash-pub/dist/index.js +76 -19
  49. package/plugins/publishings/emdash-pub/src/index.ts +4 -0
  50. package/plugins/publishings/infoq-pub/dist/index.js +74 -21
  51. package/plugins/publishings/juejin-pub/dist/index.js +74 -21
  52. package/plugins/publishings/medium-pub/dist/index.js +77 -19
  53. package/plugins/publishings/medium-pub/src/index.ts +5 -0
  54. package/plugins/publishings/podcast-pub/dist/index.js +130 -34
  55. package/plugins/publishings/podcast-pub/src/index.ts +20 -5
  56. package/plugins/publishings/podcast-pub/src/map.ts +11 -0
  57. package/plugins/publishings/podcast-pub/src/show-notes.ts +66 -13
  58. package/plugins/publishings/qiita-pub/dist/index.js +75 -18
  59. package/plugins/publishings/qiita-pub/src/index.ts +4 -0
  60. package/plugins/publishings/substack-pub/dist/index.js +74 -21
  61. package/plugins/publishings/surfdash-pub/dist/index.js +99 -62
  62. package/plugins/publishings/surfdash-pub/src/index.ts +60 -19
  63. package/plugins/publishings/wechatmp-pub/dist/index.js +79 -22
  64. package/plugins/publishings/wechatmp-pub/src/index.ts +12 -3
  65. package/plugins/publishings/x-pub/dist/index.js +56 -37
  66. package/plugins/publishings/x-pub/src/index.ts +4 -0
  67. package/plugins/publishings/xhs-pub/dist/index.js +74 -21
  68. package/plugins/publishings/zenn-pub/dist/index.js +103 -25
  69. package/plugins/publishings/zenn-pub/src/index.ts +43 -9
@@ -3,7 +3,8 @@
3
3
  name: kk-itc
4
4
  kind: state-machine
5
5
  description: >-
6
- IT content authoring pipeline using topic/itc-generating, Spur HITL gates, and optional judging
6
+ IT content authoring pipeline using topic/itc-generating, Spur HITL gates, and optional judging;
7
+ an auto path (auto-picked outline, unslop pass, judge revise loop) ends in a run report
7
8
  initialState: prepare
8
9
  terminalStates:
9
10
  - done
@@ -19,6 +20,9 @@ vars:
19
20
  playbook: "generic"
20
21
  research: "false"
21
22
  judge: "false"
23
+ auto: "false" # auto mode: writer-recommended outline, no draft-review pause, mandatory judge, auto revise loop
24
+ unslop: "false" # run kk:taste-unslop on the draft before review/judge
25
+ max_revisions: "2" # cap on the auto revise loop (interactive stays bounded by the existing 3)
22
26
  outline: ""
23
27
  force: "false"
24
28
  rubric: "tech-accuracy"
@@ -26,6 +30,13 @@ vars:
26
30
  agent: ""
27
31
  __hitlAnswer: ""
28
32
  __hitlInput: ""
33
+ __verdictFeedback: "" # raw .itc-verdict.json, read by judge so draft-revise can show the feedback
34
+ publish_targets: "" # comma list of publish plugin names; empty = no publish tail (V1)
35
+ publish_live: "false" # live instead of draft; launch-only, never implied by auto (V4)
36
+ source_locale: "en" # locale of the authored draft (en|zh|ja)
37
+ cover_enabled: "false" # generate a cover via kk:image-authoring — this is the spend approval (R7)
38
+ inline_images: "false" # also generate inline illustrations — also a spend approval
39
+ browser_target: "" # internal cursor for the browser publish loop (written by itc-publish-next)
29
40
 
30
41
  states:
31
42
  - id: prepare
@@ -62,6 +73,7 @@ states:
62
73
  input: |
63
74
  Invoke the kk:${vars.writer} skill.
64
75
  Generate outline options (outline-option-a.md, outline-option-b.md, and optionally outline-option-c.md) in ${vars.work_dir}/2-outline/ from the brief at ${vars.work_dir}/brief.md using playbook ${vars.playbook}.
76
+ When auto mode is on (auto=true), also write 2-outline/outline-recommendation.json as {"pick": "a|b|c", "rationale": "<why this option is strongest>"} recommending the option you would commit.
65
77
  Do not wait for operator selection; write the option files.
66
78
  expectFile: ${vars.work_dir}/2-outline/outline-option-a.md
67
79
  - kind: shell
@@ -82,6 +94,18 @@ states:
82
94
  - c
83
95
  var: __hitlAnswer
84
96
 
97
+ - id: outline-autopick
98
+ description: "Auto mode — validate the writer's outline-recommendation.json and bind the pick as the selected outline"
99
+ onEnter:
100
+ - kind: shell
101
+ options:
102
+ command: >-
103
+ kk stage itc-outline-pick "${vars.work_dir}"
104
+ - kind: file.read.into-var
105
+ options:
106
+ path: ${vars.work_dir}/2-outline/.auto-pick
107
+ var: outline
108
+
85
109
  - id: outline-commit
86
110
  description: "Copy selected outline to outline-approved.md"
87
111
  onEnter:
@@ -110,6 +134,21 @@ states:
110
134
  Revision feedback: ${vars.__hitlInput}
111
135
  expectFile: ${vars.work_dir}/3-draft-draft-article.md
112
136
 
137
+ - id: unslop
138
+ description: "De-slop pass — kk:taste-unslop line-edits the draft (writes a new file, then the swap makes it in place)"
139
+ onEnter:
140
+ - kind: agent.run
141
+ options:
142
+ role: scribe
143
+ agent: ${vars.agent}
144
+ input: |
145
+ Invoke the kk:taste-unslop skill.
146
+ Read ${vars.work_dir}/3-draft-draft-article.md and write the line-edited version to ${vars.work_dir}/3-draft-draft-article.new.md, removing slop (AI-tell phrasing, filler, hedging) while preserving the technical claims, code blocks, links, and the approved outline's structure. Do not modify or delete the original file; the pipeline swaps the edited file in.
147
+ expectFile: ${vars.work_dir}/3-draft-draft-article.new.md
148
+ - kind: shell
149
+ options:
150
+ command: mv -f "${vars.work_dir}/3-draft-draft-article.new.md" "${vars.work_dir}/3-draft-draft-article.md"
151
+
113
152
  - id: draft-review
114
153
  description: "Operator reviews and approves or requests revision on draft-article.md"
115
154
  pause: true
@@ -130,9 +169,139 @@ states:
130
169
  echo $((n + 1)) > "${vars.work_dir}/.revise-count";
131
170
  - kind: hitl.input
132
171
  options:
133
- prompt: "Provide specific revision feedback for ${vars.work_dir}/3-draft-draft-article.md:"
172
+ prompt: "Judge feedback (from ${vars.work_dir}/.itc-verdict.json): ${vars.__verdictFeedback}\nProvide specific revision feedback for ${vars.work_dir}/3-draft-draft-article.md:"
134
173
  var: __hitlInput
135
174
 
175
+ - id: draft-autorevise
176
+ description: "Auto mode — apply the judge feedback[] to the draft and consume one revision from the budget"
177
+ onEnter:
178
+ - kind: shell
179
+ options:
180
+ command: >-
181
+ n=$(cat "${vars.work_dir}/.auto-revise-count" 2>/dev/null || echo 0);
182
+ echo $((n + 1)) > "${vars.work_dir}/.auto-revise-count";
183
+ - kind: agent.run
184
+ options:
185
+ role: scribe
186
+ agent: ${vars.agent}
187
+ input: |
188
+ Invoke the kk:${vars.writer} skill.
189
+ Read the draft at ${vars.work_dir}/3-draft-draft-article.md and write a revised version to ${vars.work_dir}/3-draft-draft-article.new.md, applying every item of feedback[] in ${vars.work_dir}/.itc-verdict.json. Do not modify or delete the original file; the pipeline swaps the revised file in.
190
+ expectFile: ${vars.work_dir}/3-draft-draft-article.new.md
191
+ - kind: shell
192
+ options:
193
+ command: mv -f "${vars.work_dir}/3-draft-draft-article.new.md" "${vars.work_dir}/3-draft-draft-article.md"
194
+
195
+ - id: publish-entry
196
+ description: "Publish tail entry — targets are set; route into illustration/materialization"
197
+
198
+ - id: illustrate
199
+ description: "Optional cover/inline illustrations via kk:image-authoring — entered only when a spend var is on (R7)"
200
+ onEnter:
201
+ - kind: agent.run
202
+ options:
203
+ role: scribe
204
+ agent: ${vars.agent}
205
+ input: |
206
+ Invoke the kk:image-authoring skill with KK_NONINTERACTIVE=1 and KK_IMAGE_AUTO_CONFIRM=1 (non-interactive, auto-confirm — the operator approved spend via the cover_enabled/inline_images vars).
207
+ Create ${vars.work_dir}/4-illustrations/ and generate the cover illustration into it as cover.png (cover.jpg acceptable), sized for an article hero image.
208
+ When inline_images=true, also generate inline figures for the draft's key sections as inline-<slug>.png in the same directory.
209
+ Print each written path as the last line of stdout.
210
+ - kind: shell
211
+ options:
212
+ command: >-
213
+ test "${vars.cover_enabled}" = "true" || exit 0;
214
+ ls "${vars.work_dir}"/4-illustrations/cover.* >/dev/null 2>&1 || { echo "cover_enabled=true but no 4-illustrations/cover.* in ${vars.work_dir}" >&2; exit 1; }
215
+
216
+ - id: materialize
217
+ description: "Materialize the approved draft to 4-publish/content.json"
218
+ onEnter:
219
+ - kind: shell
220
+ options:
221
+ command: >-
222
+ kk stage itc-materialize "${vars.work_dir}" "${vars.publish_live}"
223
+
224
+ - id: publish-plan
225
+ description: "Split targets into fan-out groups and browser targets (4-publish/publish-plan.json)"
226
+ onEnter:
227
+ - kind: shell
228
+ options:
229
+ command: >-
230
+ kk stage itc-publish-plan "${vars.work_dir}" "${vars.publish_targets}" "${vars.source_locale}" "${vars.publish_live}"
231
+
232
+ - id: adapt
233
+ description: "Write one adapted Content file per plan variant with adapt:true — kk:article-adapt (R9)"
234
+ onEnter:
235
+ - kind: agent.run
236
+ options:
237
+ role: scribe
238
+ agent: ${vars.agent}
239
+ input: |
240
+ Invoke the kk:article-adapt skill.
241
+ Read ${vars.work_dir}/4-publish/publish-plan.json and, for every entry in variants with adapt=true, read the source ${vars.work_dir}/4-publish/content.json and write ${vars.work_dir}/4-publish/<entry.file>: translate title and body to the variant locale, apply the entry's limits, and keep code blocks, URLs and references unchanged.
242
+ Set format to the variant key's format suffix. Never set metadata.published, metadata.publishStatus or metadata.operation — itc-publish-fanout stamps the draft/live switches at send time.
243
+ - kind: shell
244
+ options:
245
+ command: >-
246
+ kk stage itc-adapt-verify "${vars.work_dir}"
247
+
248
+ - id: publish-gate
249
+ description: "Route to the operator confirm unless auto publishes drafts"
250
+
251
+ - id: publish-confirm
252
+ description: "Operator confirms the send — every target, draft or live mode"
253
+ pause: true
254
+ onEnter:
255
+ - kind: hitl.confirm
256
+ options:
257
+ prompt: >-
258
+ Send to targets [${vars.publish_targets}] in ${vars.publish_live} mode (false = draft,
259
+ true = LIVE)? Review ${vars.work_dir}/4-publish/publish-plan.json first.
260
+ var: __hitlAnswer
261
+ - kind: shell
262
+ options:
263
+ command: >-
264
+ test "${vars.__hitlAnswer}" = "yes" || printf declined > "${vars.work_dir}/4-publish/.publish-declined"
265
+
266
+ - id: publish-fanout
267
+ description: "Send each fan-out group through kk executor fan-out — target failures are data"
268
+ onEnter:
269
+ - kind: shell
270
+ options:
271
+ command: >-
272
+ kk stage itc-publish-fanout "${vars.work_dir}"
273
+
274
+ - id: publish-retry
275
+ description: "Re-send failed fan-out groups once through --retry-from (V5)"
276
+ onEnter:
277
+ - kind: shell
278
+ options:
279
+ command: >-
280
+ n=$(cat "${vars.work_dir}/.publish-retry-count" 2>/dev/null || echo 0);
281
+ echo $((n + 1)) > "${vars.work_dir}/.publish-retry-count";
282
+ kk stage itc-publish-fanout "${vars.work_dir}" --retry
283
+
284
+ - id: publish-agent
285
+ description: "Publish one pending browser target via kk:publish — file-cursor loop bounded by the plan"
286
+ onEnter:
287
+ - kind: file.read.into-var
288
+ options:
289
+ path: ${vars.work_dir}/4-publish/.next-browser
290
+ var: browser_target
291
+ - kind: agent.run
292
+ options:
293
+ role: scribe
294
+ agent: ${vars.agent}
295
+ input: |
296
+ Invoke the kk:publish skill for the browser target ${vars.browser_target}.
297
+ Read ${vars.work_dir}/4-publish/publish-plan.json, find the browser entry whose target is ${vars.browser_target}, and use that variant's file under ${vars.work_dir}/4-publish/ as the Content input.
298
+ When the plan's live is true pass the skill's --live flag; otherwise publish as a draft (V4).
299
+ Always write the Result to ${vars.work_dir}/4-publish/result.${vars.browser_target}.json, including {ok: false, error: ...} when the publish fails.
300
+ expectFile: ${vars.work_dir}/4-publish/result.${vars.browser_target}.json
301
+ - kind: shell
302
+ options:
303
+ command: 'kk stage itc-publish-next "${vars.work_dir}"'
304
+
136
305
  - id: judge
137
306
  description: "Evaluate technical draft with content-judge (agent.run)"
138
307
  onEnter:
@@ -143,9 +312,22 @@ states:
143
312
  input: |
144
313
  Invoke the kk:content-judge skill.
145
314
  Evaluate the draft at ${vars.work_dir}/3-draft-draft-article.md against the ${vars.rubric} rubric.
315
+ Research evidence: if ${vars.work_dir}/docs.json exists, read it and weigh it when judging.
146
316
  Write the verdict JSON to ${vars.work_dir}/.itc-verdict.json per the skill's verdict contract.
147
317
  Print the verdict path as the last line of stdout.
148
318
  expectFile: ${vars.work_dir}/.itc-verdict.json
319
+ - kind: file.read.into-var
320
+ options:
321
+ path: ${vars.work_dir}/.itc-verdict.json
322
+ var: __verdictFeedback
323
+
324
+ - id: report
325
+ description: "Write the run report, then route to done or failed on its outcome"
326
+ onEnter:
327
+ - kind: shell
328
+ options:
329
+ command: >-
330
+ kk stage itc-report "${vars.work_dir}" "${vars.max_revisions}"
149
331
 
150
332
  - id: done
151
333
  description: "Terminal — IT content draft generated and approved successfully"
@@ -175,13 +357,21 @@ transitions:
175
357
  guard:
176
358
  kind: always
177
359
 
360
+ - from: outline-write
361
+ to: outline-autopick
362
+ description: "Auto mode with no pre-selected outline -> validate the writer recommendation and bind it"
363
+ guard:
364
+ kind: shell
365
+ options:
366
+ command: 'test "${vars.auto}" = "true" -a -z "${vars.outline}"'
367
+
178
368
  - from: outline-write
179
369
  to: outline-select
180
- description: "Outline not pre-selected -> pause for operator selection"
370
+ description: "Interactive mode with no pre-selected outline -> pause for operator selection"
181
371
  guard:
182
372
  kind: shell
183
373
  options:
184
- command: 'test -z "${vars.outline}"'
374
+ command: 'test "${vars.auto}" != "true" -a -z "${vars.outline}"'
185
375
 
186
376
  - from: outline-write
187
377
  to: outline-commit
@@ -197,17 +387,57 @@ transitions:
197
387
  guard:
198
388
  kind: always
199
389
 
390
+ - from: outline-autopick
391
+ to: outline-commit
392
+ description: "Writer recommendation validated and bound -> commit approved outline"
393
+ guard:
394
+ kind: always
395
+
200
396
  - from: outline-commit
201
397
  to: draft-write
202
398
  description: "Approved outline committed -> write draft"
203
399
  guard:
204
400
  kind: always
205
401
 
402
+ - from: draft-write
403
+ to: unslop
404
+ description: "Unslop enabled -> de-slop the fresh draft"
405
+ guard:
406
+ kind: shell
407
+ options:
408
+ command: 'test "${vars.unslop}" = "true"'
409
+
206
410
  - from: draft-write
207
411
  to: draft-review
208
- description: "Draft written -> pause for operator review"
412
+ description: "Interactive mode without unslop -> pause for operator review"
209
413
  guard:
210
- kind: always
414
+ kind: shell
415
+ options:
416
+ command: 'test "${vars.auto}" != "true" -a "${vars.unslop}" != "true"'
417
+
418
+ - from: draft-write
419
+ to: judge
420
+ description: "Auto mode without unslop -> straight to the judge"
421
+ guard:
422
+ kind: shell
423
+ options:
424
+ command: 'test "${vars.auto}" = "true" -a "${vars.unslop}" != "true"'
425
+
426
+ - from: unslop
427
+ to: judge
428
+ description: "Auto mode -> the de-slopped draft goes to the judge"
429
+ guard:
430
+ kind: shell
431
+ options:
432
+ command: 'test "${vars.auto}" = "true"'
433
+
434
+ - from: unslop
435
+ to: draft-review
436
+ description: "Interactive mode -> pause for operator review of the de-slopped draft"
437
+ guard:
438
+ kind: shell
439
+ options:
440
+ command: 'test "${vars.auto}" != "true"'
211
441
 
212
442
  - from: draft-review
213
443
  to: judge
@@ -219,11 +449,19 @@ transitions:
219
449
 
220
450
  - from: draft-review
221
451
  to: done
222
- description: "Draft approved and judge disabled -> complete workflow"
452
+ description: "Draft approved, judge disabled, no publish targets -> complete workflow"
453
+ guard:
454
+ kind: shell
455
+ options:
456
+ command: '{ test -z "${vars.__hitlAnswer}" || test "${vars.__hitlAnswer}" = "yes"; } && test "${vars.judge}" != "true" && test -z "${vars.publish_targets}"'
457
+
458
+ - from: draft-review
459
+ to: publish-entry
460
+ description: "Draft approved, judge disabled, targets set -> enter the publish tail"
223
461
  guard:
224
462
  kind: shell
225
463
  options:
226
- command: '{ test -z "${vars.__hitlAnswer}" || test "${vars.__hitlAnswer}" = "yes"; } && test "${vars.judge}" != "true"'
464
+ command: '{ test -z "${vars.__hitlAnswer}" || test "${vars.__hitlAnswer}" = "yes"; } && test "${vars.judge}" != "true" && test -n "${vars.publish_targets}"'
227
465
 
228
466
  - from: draft-review
229
467
  to: draft-revise
@@ -247,18 +485,229 @@ transitions:
247
485
  guard:
248
486
  kind: always
249
487
 
488
+ - from: draft-autorevise
489
+ to: unslop
490
+ description: "Unslop enabled -> de-slop the auto-revised draft"
491
+ guard:
492
+ kind: shell
493
+ options:
494
+ command: 'test "${vars.unslop}" = "true"'
495
+
496
+ - from: draft-autorevise
497
+ to: judge
498
+ description: "Auto mode without unslop -> back to the judge"
499
+ guard:
500
+ kind: shell
501
+ options:
502
+ command: 'test "${vars.auto}" = "true" -a "${vars.unslop}" != "true"'
503
+
504
+ - from: judge
505
+ to: done
506
+ description: "Interactive mode, verdict PASS (or empty in dry-run), no publish targets -> complete workflow"
507
+ guard:
508
+ kind: shell
509
+ options:
510
+ command: '{ test "${vars.auto}" != "true"; } && { v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -z "$v" -o "$v" = PASS; } && test -z "${vars.publish_targets}"'
511
+
512
+ - from: judge
513
+ to: publish-entry
514
+ description: "Verdict PASS with targets set -> enter the publish tail (auto runs report after the tail)"
515
+ guard:
516
+ kind: shell
517
+ options:
518
+ command: '{ v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -z "$v" -o "$v" = PASS; } && test -n "${vars.publish_targets}"'
519
+
250
520
  - from: judge
521
+ to: report
522
+ description: "Auto mode -> the run ends in the report (PASS without targets, FAIL, or exhausted NEEDS_REVISION)"
523
+ guard:
524
+ kind: shell
525
+ options:
526
+ command: '{ test "${vars.auto}" = "true"; } && { v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; c="$(cat "${vars.work_dir}/.auto-revise-count" 2>/dev/null || echo 0)"; { test -z "$v" -o "$v" = PASS; } || test "$v" = FAIL || { test "$v" = NEEDS_REVISION -a "$c" -ge "${vars.max_revisions}"; }; }'
527
+
528
+ - from: judge
529
+ to: draft-autorevise
530
+ description: "Auto mode, NEEDS_REVISION with revise budget left -> apply feedback and re-judge"
531
+ guard:
532
+ kind: shell
533
+ options:
534
+ command: '{ test "${vars.auto}" = "true"; } && { v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; c="$(cat "${vars.work_dir}/.auto-revise-count" 2>/dev/null || echo 0)"; test "$v" = NEEDS_REVISION -a "$c" -lt "${vars.max_revisions}"; }'
535
+
536
+ - from: judge
537
+ to: draft-revise
538
+ description: "Interactive mode, NEEDS_REVISION with revise budget left -> collect revision with the feedback shown"
539
+ guard:
540
+ kind: shell
541
+ options:
542
+ command: '{ test "${vars.auto}" != "true"; } && { v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; c="$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0)"; test "$v" = NEEDS_REVISION -a "$c" -lt 3; }'
543
+
544
+ - from: judge
545
+ to: failed
546
+ description: "Interactive mode, verdict FAIL or revise budget exhausted -> fail"
547
+ guard:
548
+ kind: shell
549
+ options:
550
+ command: '{ test "${vars.auto}" != "true"; } && { v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; c="$(cat "${vars.work_dir}/.revise-count" 2>/dev/null || echo 0)"; test "$v" = FAIL || { test "$v" = NEEDS_REVISION -a "$c" -ge 3; }; }'
551
+
552
+ # --- 0151 publish tail: materialize -> plan -> gate -> confirm/fanout -> retry -> browser loop ---
553
+
554
+ - from: publish-entry
555
+ to: illustrate
556
+ description: "Cover or inline images approved -> run the illustration step (R7: no image spend while both vars are false)"
557
+ guard:
558
+ kind: shell
559
+ options:
560
+ command: 'test "${vars.cover_enabled}" = "true" -o "${vars.inline_images}" = "true"'
561
+
562
+ - from: publish-entry
563
+ to: materialize
564
+ description: "No illustration spend approved -> materialize directly"
565
+ guard:
566
+ kind: shell
567
+ options:
568
+ command: 'test "${vars.cover_enabled}" != "true" -a "${vars.inline_images}" != "true"'
569
+
570
+ - from: illustrate
571
+ to: materialize
572
+ description: "Illustrations written -> materialize the final draft (metadata.coverImage picks up 4-illustrations/cover.*)"
573
+ guard:
574
+ kind: always
575
+
576
+ - from: materialize
577
+ to: publish-plan
578
+ description: "content.json written -> split targets into groups"
579
+ guard:
580
+ kind: always
581
+
582
+ - from: publish-plan
583
+ to: adapt
584
+ description: "The plan has at least one adapt:true variant -> write the adapted variant files (R9)"
585
+ guard:
586
+ kind: shell
587
+ options:
588
+ command: >-
589
+ v="$(jq '[.variants[] | select(.adapt == true)] | length' "${vars.work_dir}/4-publish/publish-plan.json" 2>/dev/null)";
590
+ test -n "$v" -a "$v" -gt 0
591
+
592
+ - from: publish-plan
593
+ to: publish-gate
594
+ description: "Nothing needs adaptation -> route through the send gate"
595
+ guard:
596
+ kind: always
597
+
598
+ - from: adapt
599
+ to: publish-gate
600
+ description: "Variant files verified (itc-adapt-verify) -> route through the send gate"
601
+ guard:
602
+ kind: always
603
+
604
+ - from: publish-gate
605
+ to: publish-confirm
606
+ description: "Interactive run or live publish -> pause for the operator answer (V4)"
607
+ guard:
608
+ kind: shell
609
+ options:
610
+ command: >-
611
+ test "${vars.auto}" != "true" -o "${vars.publish_live}" = "true"
612
+
613
+ - from: publish-gate
614
+ to: publish-fanout
615
+ description: "Auto draft run -> send without pausing (ADR-022)"
616
+ guard:
617
+ kind: always
618
+
619
+ - from: publish-confirm
620
+ to: publish-fanout
621
+ description: "Operator confirmed -> send"
622
+ guard:
623
+ kind: shell
624
+ options:
625
+ command: 'test "${vars.__hitlAnswer}" = "yes"'
626
+
627
+ - from: publish-confirm
628
+ to: report
629
+ description: "Operator declined (or dry-run left no answer) -> report without any publish call"
630
+ guard:
631
+ kind: shell
632
+ options:
633
+ command: >-
634
+ test -z "${vars.__hitlAnswer}" -o "${vars.__hitlAnswer}" = "no"
635
+
636
+ - from: publish-fanout
637
+ to: publish-retry
638
+ description: "A fan-out group has ok:false and the retry budget is untouched -> re-send once (V5)"
639
+ guard:
640
+ kind: shell
641
+ options:
642
+ command: >-
643
+ test "$(cat "${vars.work_dir}/.publish-retry-count" 2>/dev/null || echo 0)" -lt 1
644
+ -a -s "${vars.work_dir}/4-publish/.fanout-failed"
645
+
646
+ - from: publish-fanout
647
+ to: publish-agent
648
+ description: "A browser target has no result.<target>.json -> run the kk:publish loop"
649
+ guard:
650
+ kind: shell
651
+ options:
652
+ # .next-browser cursor: seeded by itc-publish-fanout, recomputed after each kk:publish step
653
+ command: 'test -s "${vars.work_dir}/4-publish/.next-browser"'
654
+
655
+ - from: publish-fanout
656
+ to: report
657
+ description: "Otherwise -> report the per-target outcomes"
658
+ guard:
659
+ kind: always
660
+
661
+ - from: publish-retry
662
+ to: publish-agent
663
+ description: "Retry done, a browser target is still pending -> run the kk:publish loop"
664
+ guard:
665
+ kind: shell
666
+ options:
667
+ # .next-browser cursor: seeded by itc-publish-fanout, recomputed after each kk:publish step
668
+ command: 'test -s "${vars.work_dir}/4-publish/.next-browser"'
669
+
670
+ - from: publish-retry
671
+ to: report
672
+ description: "Otherwise -> report (remaining fan-out failures are terminal data)"
673
+ guard:
674
+ kind: always
675
+
676
+ - from: publish-agent
677
+ to: publish-agent
678
+ description: "A browser target is still pending -> next cursor iteration (bounded by the plan, V5)"
679
+ guard:
680
+ kind: shell
681
+ options:
682
+ # .next-browser cursor: seeded by itc-publish-fanout, recomputed after each kk:publish step
683
+ command: 'test -s "${vars.work_dir}/4-publish/.next-browser"'
684
+
685
+ - from: publish-agent
686
+ to: report
687
+ description: "Browser list exhausted -> report"
688
+ guard:
689
+ kind: always
690
+
691
+ - from: report
251
692
  to: done
252
- description: "Judge verdict is PASS (or empty in dry-run) -> complete workflow"
693
+ description: "Report outcome done or declined (empty outcome = done in dry-run, mirroring the empty-verdict PASS convention)"
694
+ guard:
695
+ kind: shell
696
+ options:
697
+ command: 'o="$(jq -r .outcome ${vars.work_dir}/5-report/report.json 2>/dev/null)"; test -z "$o" -o "$o" = done -o "$o" = declined'
698
+
699
+ - from: report
700
+ to: failed
701
+ description: "Report outcome failed -> fail"
253
702
  guard:
254
703
  kind: shell
255
704
  options:
256
- command: 'v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -z "$v" -o "$v" = PASS'
705
+ command: 'o="$(jq -r .outcome ${vars.work_dir}/5-report/report.json 2>/dev/null)"; test -n "$o" -a "$o" != done'
257
706
 
258
707
  - from: judge
259
708
  to: failed
260
- description: "Judge verdict is not PASS -> fail"
709
+ description: "Catch-all: an out-of-contract verdict string fails the run instead of deadlocking the machine (0149 review P3)"
261
710
  guard:
262
711
  kind: shell
263
712
  options:
264
- command: 'v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -n "$v" -a "$v" != PASS'
713
+ command: 'v="$(jq -r .verdict ${vars.work_dir}/.itc-verdict.json 2>/dev/null)"; test -n "$v" -a "$v" != PASS -a "$v" != FAIL -a "$v" != NEEDS_REVISION'