minimal-agent 0.8.2 → 0.10.0

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 (484) hide show
  1. package/README.md +14 -12
  2. package/package.json +34 -1
  3. package/plugins/cron-runner/.claude-plugin/plugin.json +5 -0
  4. package/plugins/cron-runner/commands/cron.md +26 -0
  5. package/plugins/cron-runner/commands/crons.md +7 -0
  6. package/plugins/cron-runner/plugin.js +34 -0
  7. package/plugins/cron-runner/src/commands.js +348 -0
  8. package/plugins/cron-runner/src/cronTime.js +148 -0
  9. package/plugins/cron-runner/src/lock.js +68 -0
  10. package/plugins/cron-runner/src/runs.js +89 -0
  11. package/plugins/cron-runner/src/scheduleEngine.js +72 -0
  12. package/plugins/cron-runner/src/scheduler.js +355 -0
  13. package/plugins/cron-runner/src/schema.js +140 -0
  14. package/plugins/cron-runner/src/service.js +167 -0
  15. package/plugins/cron-runner/src/store.js +298 -0
  16. package/plugins/cron-runner/src/types.js +1 -0
  17. package/plugins/workflow-runner/commands/workflow.md +4 -4
  18. package/plugins/workflow-runner/commands/workflows.md +1 -1
  19. package/plugins/workflow-runner/plugin.js +3 -1
  20. package/plugins/workflow-runner/src/agentCommon.js +249 -51
  21. package/plugins/workflow-runner/src/dslManifest.js +72 -0
  22. package/plugins/workflow-runner/src/expressions.js +198 -15
  23. package/plugins/workflow-runner/src/index.js +40 -8
  24. package/plugins/workflow-runner/src/jsonPayload.js +1 -1
  25. package/plugins/workflow-runner/src/loader.js +286 -72
  26. package/plugins/workflow-runner/src/multimodal.js +37 -0
  27. package/plugins/workflow-runner/src/recovery.js +49 -39
  28. package/plugins/workflow-runner/src/runner.js +802 -287
  29. package/plugins/workflow-runner/src/stepExecutors/agent.js +157 -39
  30. package/plugins/workflow-runner/src/stepExecutors/assert.js +16 -3
  31. package/plugins/workflow-runner/src/stepExecutors/llm.js +60 -111
  32. package/plugins/workflow-runner/src/stepExecutors/skill.js +47 -47
  33. package/plugins/workflow-runner/src/stepExecutors/tool.js +76 -10
  34. package/plugins/workflow-runner/src/stepExecutors/verify.js +27 -10
  35. package/plugins/workflow-runner/src/taskIdentity.js +296 -0
  36. package/plugins/workflow-runner/src/types.js +19 -9
  37. package/plugins/workflow-runner/src/workflowState.js +516 -33
  38. package/skills/adversarial-review/SKILL.md +0 -1
  39. package/skills/ai-image/SKILL.md +89 -0
  40. package/skills/ai-image/scripts/generate.mjs +497 -0
  41. package/skills/ai-image/scripts/generate_from_plan.mjs +469 -0
  42. package/skills/ai-image/scripts/generate_from_plan_test.mjs +223 -0
  43. package/skills/ai-image/scripts/generate_test.mjs +74 -0
  44. package/skills/browser-automation/SKILL.md +47 -0
  45. package/skills/docx/SKILL.md +25 -3
  46. package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
  47. package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
  48. package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
  49. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  50. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
  51. package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
  52. package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
  53. package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
  54. package/skills/docx/scripts/opc_check.py +253 -0
  55. package/skills/image-gen-openrouter/SKILL.md +10 -2
  56. package/skills/image-stats/SKILL.md +65 -0
  57. package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
  58. package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
  59. package/skills/image-stats/scripts/image_stats.py +368 -0
  60. package/skills/image-stats/scripts/image_stats_test.py +181 -0
  61. package/skills/pptx/SKILL.md +123 -95
  62. package/skills/pptx/design.md +82 -0
  63. package/skills/pptx/examples/README.md +29 -0
  64. package/skills/pptx/examples/hybrid_example.mjs +107 -0
  65. package/skills/pptx/examples/hybrid_example.pptx +0 -0
  66. package/skills/pptx/pptxgenjs.md +41 -0
  67. package/skills/pptx/scripts/deck_helpers.mjs +224 -0
  68. package/skills/pptx/scripts/layout_lint.py +293 -0
  69. package/skills/pptx/scripts/layout_lint_test.py +160 -0
  70. package/skills/pptx/scripts/opc_check.py +339 -0
  71. package/skills/pptx/scripts/svg_fallback.mjs +145 -0
  72. package/skills/pptx/svg.md +67 -0
  73. package/skills/tts-zh/SKILL.md +19 -2
  74. package/skills/ui-design/SKILL.md +158 -0
  75. package/skills/ui-design/claude_design.md +309 -0
  76. package/skills/ui-design/evals/evals.json +254 -0
  77. package/skills/ui-design/references/aesthetic-direction.md +83 -0
  78. package/skills/ui-design/references/claude-design-protocol.md +36 -0
  79. package/skills/ui-design/references/design-context.md +53 -0
  80. package/skills/ui-design/references/design-execution-playbook.md +82 -0
  81. package/skills/ui-design/references/export-pptx.md +124 -0
  82. package/skills/ui-design/references/layout-composition.md +654 -0
  83. package/skills/ui-design/references/preview-feedback.md +37 -0
  84. package/skills/ui-design/references/source-image-layout.md +189 -0
  85. package/skills/ui-design/references/starter-components.md +78 -0
  86. package/skills/ui-design/references/vi-aegis-vector.md +144 -0
  87. package/skills/ui-design/references/vi-amber-prism.md +133 -0
  88. package/skills/ui-design/references/vi-aqua-glass.md +200 -0
  89. package/skills/ui-design/references/vi-comfort-vision.md +147 -0
  90. package/skills/ui-design/references/vi-ember-prism.md +140 -0
  91. package/skills/ui-design/references/vi-nebula-console.md +151 -0
  92. package/skills/ui-design/references/vi-obsidian-optics.md +139 -0
  93. package/skills/ui-design/references/vi-obsidian-xui.md +143 -0
  94. package/skills/ui-design/references/vi-precision-horizon-dark.md +117 -0
  95. package/skills/ui-design/references/vi-precision-horizon.md +215 -0
  96. package/skills/ui-design/references/vi-solar-relay.md +130 -0
  97. package/skills/ui-design/references/vi-template-workflow.md +48 -0
  98. package/skills/ui-design/references/vi-verdant-grid.md +141 -0
  99. package/skills/ui-design/references/vi-violet-meridian.md +172 -0
  100. package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
  101. package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
  102. package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
  103. package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
  104. package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
  105. package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
  106. package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
  107. package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
  108. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
  109. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
  110. package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
  111. package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
  112. package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
  113. package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
  114. package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
  115. package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
  116. package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
  117. package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
  118. package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
  119. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
  120. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
  121. package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
  122. package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
  123. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
  124. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
  125. package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
  126. package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
  127. package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
  128. package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
  129. package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
  130. package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
  131. package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
  132. package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
  133. package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
  134. package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
  135. package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
  136. package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
  137. package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
  138. package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
  139. package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
  140. package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
  141. package/skills/ui-design/scripts/assemble_material.py +217 -0
  142. package/skills/ui-design/scripts/assemble_material_test.py +149 -0
  143. package/skills/ui-design/scripts/browser_check_ui_artifact.mjs +221 -0
  144. package/skills/ui-design/scripts/chart_sanity_check.py +261 -0
  145. package/skills/ui-design/scripts/chart_sanity_check_test.py +165 -0
  146. package/skills/ui-design/scripts/check_language_policy.py +351 -0
  147. package/skills/ui-design/scripts/check_ui_artifact.py +435 -0
  148. package/skills/ui-design/scripts/check_ui_artifact_pptx_test.py +251 -0
  149. package/skills/ui-design/scripts/deck_pages_check.py +158 -0
  150. package/skills/ui-design/scripts/deck_pages_check_test.py +134 -0
  151. package/skills/ui-design/scripts/deck_visual_style_check.py +767 -0
  152. package/skills/ui-design/scripts/deck_visual_style_check_test.py +713 -0
  153. package/skills/ui-design/scripts/design_budget_check.py +271 -0
  154. package/skills/ui-design/scripts/design_budget_check_test.py +183 -0
  155. package/skills/ui-design/scripts/design_repair_hints.py +162 -0
  156. package/skills/ui-design/scripts/design_repair_hints_test.py +54 -0
  157. package/skills/ui-design/scripts/design_style_check.py +397 -0
  158. package/skills/ui-design/scripts/design_style_check_test.py +233 -0
  159. package/skills/ui-design/scripts/draft_coverage_check.py +184 -0
  160. package/skills/ui-design/scripts/draft_coverage_check_test.py +131 -0
  161. package/skills/ui-design/scripts/export_pptx_from_html.mjs +2367 -0
  162. package/skills/ui-design/scripts/extract_source_assets.py +607 -0
  163. package/skills/ui-design/scripts/extract_source_assets_test.py +256 -0
  164. package/skills/ui-design/scripts/generated_image_review_collect.py +206 -0
  165. package/skills/ui-design/scripts/generated_image_review_collect_test.py +91 -0
  166. package/skills/ui-design/scripts/image_plan_lint.py +571 -0
  167. package/skills/ui-design/scripts/image_plan_lint_test.py +515 -0
  168. package/skills/ui-design/scripts/image_prompt_rewrite.py +713 -0
  169. package/skills/ui-design/scripts/image_prompt_rewrite_test.py +966 -0
  170. package/skills/ui-design/scripts/layout_balance.py +881 -0
  171. package/skills/ui-design/scripts/layout_balance_test.py +927 -0
  172. package/skills/ui-design/scripts/normalize_design_json.py +272 -0
  173. package/skills/ui-design/scripts/normalize_design_json_test.py +119 -0
  174. package/skills/ui-design/scripts/plan_source_layout.py +1450 -0
  175. package/skills/ui-design/scripts/plan_source_layout_test.py +1136 -0
  176. package/skills/ui-design/scripts/resolve_source_input.py +270 -0
  177. package/skills/ui-design/scripts/resolve_source_input_test.py +98 -0
  178. package/skills/ui-design/scripts/scaffold_ui_artifact.py +377 -0
  179. package/skills/ui-design/scripts/source_usage_check.py +581 -0
  180. package/skills/ui-design/scripts/source_usage_check_test.py +427 -0
  181. package/skills/ui-design/scripts/text_readability_pixel.py +340 -0
  182. package/skills/ui-design/scripts/text_readability_pixel_test.py +219 -0
  183. package/skills/ui-design/scripts/visual_quality_gate.py +301 -0
  184. package/skills/ui-design/scripts/visual_quality_gate_test.py +233 -0
  185. package/skills/ui-design/tests/e2e/prompts/deck.md +19 -0
  186. package/skills/ui-design/tests/e2e/prompts/webpage.md +17 -0
  187. package/skills/ui-design/tests/e2e/render_check.mjs +101 -0
  188. package/skills/ui-design/tests/e2e/rubric.json +54 -0
  189. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/browser-check.json +49 -0
  190. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/language-check.txt +12 -0
  191. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/static-check.txt +15 -0
  192. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/outputs/index.html +837 -0
  193. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/prompt.md +12 -0
  194. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/review.md +21 -0
  195. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/desktop.png +0 -0
  196. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/mobile.png +0 -0
  197. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/homepage.html +373 -0
  198. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/platform.html +378 -0
  199. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/prompt.md +13 -0
  200. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/review.md +26 -0
  201. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
  202. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
  203. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
  204. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
  205. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
  206. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
  207. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/checks/static-check.txt +2 -0
  208. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/outputs/index.html +656 -0
  209. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/prompt.md +12 -0
  210. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/render_check.mjs +67 -0
  211. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/checks/static-check.txt +2 -0
  212. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/outputs/index.html +587 -0
  213. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/prompt.md +12 -0
  214. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/review.md +36 -0
  215. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/browser-check.json +49 -0
  216. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/language-check.txt +8 -0
  217. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/static-check.txt +16 -0
  218. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/outputs/index.html +739 -0
  219. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/prompt.md +11 -0
  220. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/review.md +22 -0
  221. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/desktop.png +0 -0
  222. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/mobile.png +0 -0
  223. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/checks/browser-check.json +52 -0
  224. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/outputs/index.html +641 -0
  225. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/desktop.png +0 -0
  226. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/mobile.png +0 -0
  227. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/outputs/index.html +467 -0
  228. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/browser-check.json +49 -0
  229. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/desktop.png +0 -0
  230. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/mobile.png +0 -0
  231. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/homepage.html +373 -0
  232. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/platform.html +378 -0
  233. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/prompt.md +13 -0
  234. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/review.md +26 -0
  235. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
  236. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
  237. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
  238. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
  239. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
  240. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
  241. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/browser-check.json +49 -0
  242. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/language-check.txt +4 -0
  243. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/static-check.txt +2 -0
  244. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/execution_notes.md +10 -0
  245. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/outputs/index.html +587 -0
  246. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/prompt.md +14 -0
  247. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/review.md +13 -0
  248. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/desktop.png +0 -0
  249. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/mobile.png +0 -0
  250. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/browser-check.json +24 -0
  251. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/static-check.txt +2 -0
  252. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/execution_notes.md +21 -0
  253. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/outputs/deck.html +451 -0
  254. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-01.png +0 -0
  255. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-02.png +0 -0
  256. package/skills/ui-design/tests/e2e/runs/iteration-1/review.md +79 -0
  257. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/browser-check.json +26 -0
  258. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/static-check.txt +2 -0
  259. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/execution_notes.md +20 -0
  260. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/outputs/index.html +534 -0
  261. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/desktop.png +0 -0
  262. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/mobile.png +0 -0
  263. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/browser-check.json +64 -0
  264. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/language-check.txt +7 -0
  265. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/quick-validate.txt +1 -0
  266. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-console.txt +2 -0
  267. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-homepage.txt +2 -0
  268. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/console.html +600 -0
  269. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/homepage.html +556 -0
  270. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/prompt.md +29 -0
  271. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/review.md +57 -0
  272. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-desktop.png +0 -0
  273. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-mobile.png +0 -0
  274. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-desktop.png +0 -0
  275. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-mobile.png +0 -0
  276. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/browser-check.json +33 -0
  277. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/language-check.txt +6 -0
  278. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/quick-validate.txt +1 -0
  279. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/static-check.txt +2 -0
  280. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/outputs/index.html +682 -0
  281. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/prompt.md +13 -0
  282. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/review.md +59 -0
  283. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/desktop.png +0 -0
  284. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/mobile.png +0 -0
  285. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-01.html +466 -0
  286. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-02.html +433 -0
  287. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/prompt.md +13 -0
  288. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/browser-check.json +49 -0
  289. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/desktop.png +0 -0
  290. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/mobile.png +0 -0
  291. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/browser-check.json +49 -0
  292. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/desktop.png +0 -0
  293. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/mobile.png +0 -0
  294. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/browser-check.json +49 -0
  295. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/language-check.txt +3 -0
  296. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/static-check.txt +2 -0
  297. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/execution_notes.md +24 -0
  298. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/outputs/index.html +723 -0
  299. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/prompt.md +15 -0
  300. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/review.md +26 -0
  301. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/desktop.png +0 -0
  302. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/mobile.png +0 -0
  303. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-dark.json +49 -0
  304. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-light.json +49 -0
  305. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/language-check.txt +11 -0
  306. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-dark.txt +2 -0
  307. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-light.txt +3 -0
  308. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/execution_notes.md +23 -0
  309. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/dark.html +392 -0
  310. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/light.html +476 -0
  311. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/prompt.md +23 -0
  312. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/review.md +41 -0
  313. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/desktop.png +0 -0
  314. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/mobile.png +0 -0
  315. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/desktop.png +0 -0
  316. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/mobile.png +0 -0
  317. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/browser-check.json +54 -0
  318. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/language-check.txt +5 -0
  319. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/quick-validate.txt +1 -0
  320. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/static-check.txt +2 -0
  321. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/outputs/index.html +765 -0
  322. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/prompt.md +15 -0
  323. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/review.md +59 -0
  324. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/desktop.png +0 -0
  325. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/mobile.png +0 -0
  326. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/outputs/index.html +508 -0
  327. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/browser-check.json +49 -0
  328. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/desktop.png +0 -0
  329. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/mobile.png +0 -0
  330. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/browser-check.json +54 -0
  331. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/language-check.txt +6 -0
  332. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/quick-validate.txt +1 -0
  333. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/static-check.txt +2 -0
  334. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/outputs/index.html +788 -0
  335. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/prompt.md +14 -0
  336. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/review.md +60 -0
  337. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/desktop.png +0 -0
  338. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/mobile.png +0 -0
  339. package/skills/video-compose/SKILL.md +8 -1
  340. package/skills/web-crawler/SKILL.md +70 -0
  341. package/skills/web-crawler/scripts/crawl.mjs +538 -0
  342. package/skills/web-crawler/scripts/crawl.test.mjs +204 -0
  343. package/skills/xlsx/SKILL.md +12 -0
  344. package/skills/xlsx/scripts/opc_check.py +253 -0
  345. package/src/advisorState.js +22 -0
  346. package/src/askBridge.js +97 -3
  347. package/src/bootstrap/workingDir.js +12 -1
  348. package/src/cli/args.js +17 -1
  349. package/src/cli/configMenu.js +236 -0
  350. package/src/cli/configWizard.js +7 -5
  351. package/src/cli/print.js +37 -4
  352. package/src/cli/streamJson.js +77 -24
  353. package/src/cli/wizards/advisorWizard.js +147 -0
  354. package/src/cli/wizards/fieldForm.js +149 -0
  355. package/src/cli/wizards/imageWizard.js +60 -0
  356. package/src/cli/wizards/openRouterWizard.js +23 -0
  357. package/src/cli/wizards/providerPresets.js +95 -0
  358. package/src/cli/wizards/providerWizard.js +219 -0
  359. package/src/cli/wizards/searchWizard.js +23 -0
  360. package/src/cli/wizards/ttsWizard.js +34 -0
  361. package/src/config/configFile.js +441 -83
  362. package/src/config/configService.js +446 -0
  363. package/src/config.js +24 -64
  364. package/src/context/agentHome.js +9 -0
  365. package/src/context/archive.js +7 -2
  366. package/src/context/compact.js +8 -5
  367. package/src/context/contextLock.js +81 -0
  368. package/src/context/persistContext.js +30 -11
  369. package/src/context/reactiveCompact.js +4 -2
  370. package/src/context/recentDirs.js +21 -61
  371. package/src/context/sessionPath.js +97 -23
  372. package/src/context/sessionRegistry.js +303 -24
  373. package/src/context/tokenCounter.js +18 -0
  374. package/src/context/workspaceIndex.js +731 -0
  375. package/src/infra/verification.js +28 -15
  376. package/src/llm/client.js +394 -159
  377. package/src/llm/providers/anthropicFormat.js +241 -0
  378. package/src/llm/providers/openaiFormat.js +190 -0
  379. package/src/loop.js +219 -32
  380. package/src/main.js +61 -11
  381. package/src/messageQueue.js +97 -0
  382. package/src/multimodal.js +203 -0
  383. package/src/plugin-sdk.js +15 -0
  384. package/src/plugins/commandRouter.js +3 -0
  385. package/src/plugins/hookEngine.js +5 -1
  386. package/src/plugins/pluginLifecycle.js +28 -0
  387. package/src/plugins/pluginLoader.js +2 -1
  388. package/src/plugins/pluginRunner.js +49 -21
  389. package/src/plugins/transcript.js +4 -3
  390. package/src/prompts/pluginList.js +5 -5
  391. package/src/prompts/projectInstructions.js +3 -3
  392. package/src/prompts/promptAssembly.js +133 -144
  393. package/src/prompts/skillList.js +12 -22
  394. package/src/prompts/system.js +0 -1
  395. package/src/session/runAgentTurn.js +70 -0
  396. package/src/session/runTurn.js +41 -6
  397. package/src/toolGate.js +17 -0
  398. package/src/tools/advisor/advisor.js +379 -0
  399. package/src/tools/agent/agent.js +555 -0
  400. package/src/tools/agent/agentTypes.js +59 -0
  401. package/src/tools/agent/coordinator.js +93 -0
  402. package/src/tools/agent/worktree.js +270 -0
  403. package/src/tools/ask/ask.js +7 -2
  404. package/src/tools/bash/bash.js +112 -18
  405. package/src/tools/download/download.js +144 -0
  406. package/src/tools/edit/edit.js +1 -0
  407. package/src/tools/edit/multi-edit.js +1 -0
  408. package/src/tools/genimage/genimage.js +242 -0
  409. package/src/tools/genspeech/genspeech.js +67 -0
  410. package/src/tools/glob/glob.js +1 -0
  411. package/src/tools/grep/grep.js +3 -0
  412. package/src/tools/grep/rgPath.js +2 -0
  413. package/src/tools/index.js +25 -2
  414. package/src/tools/read/read.js +1 -0
  415. package/src/tools/shared/killTree.js +52 -0
  416. package/src/tools/toolProgressBridge.js +48 -0
  417. package/src/tools/webbrowser/agentBrowserPath.js +258 -0
  418. package/src/tools/webbrowser/browser.js +59 -42
  419. package/src/tools/webbrowser/browserControl.js +118 -0
  420. package/src/tools/webbrowser/browserDaemon.js +97 -0
  421. package/src/tools/webbrowser/browserService.js +27 -0
  422. package/src/tools/webbrowser/browserStream.js +119 -0
  423. package/src/tools/webbrowser/webbrowser.js +699 -130
  424. package/src/tools/webfetch/webfetch.js +1 -0
  425. package/src/tools/websearch/websearch.js +134 -51
  426. package/src/tools/write/write.js +1 -0
  427. package/src/ui/App.js +249 -22
  428. package/src/ui/AskQuestion.js +29 -10
  429. package/src/ui/InputBox.js +104 -12
  430. package/src/ui/LiveArea.js +112 -19
  431. package/src/ui/MessageList.js +100 -14
  432. package/src/ui/ModelPicker.js +56 -0
  433. package/src/ui/QueuedMessagesBanner.js +14 -0
  434. package/src/ui/Root.js +18 -10
  435. package/src/ui/SessionPicker.js +102 -0
  436. package/src/ui/StatusLine.js +13 -4
  437. package/src/ui/WorkspacePicker.js +55 -0
  438. package/src/ui/figures.js +44 -0
  439. package/src/ui/hooks/askSlot.js +82 -0
  440. package/src/ui/hooks/useChat.js +358 -64
  441. package/src/ui/hooks/usePasteHandler.js +11 -1
  442. package/src/ui/hooks/useTextBuffer.js +1 -3
  443. package/src/ui/liveViewport.js +5 -1
  444. package/src/ui/markdown.js +206 -0
  445. package/src/ui/textBuffer.js +0 -7
  446. package/src/ui/theme.js +32 -0
  447. package/src/utils/debugLog.js +0 -4
  448. package/src/utils/resourcePaths.js +2 -2
  449. package/src/utils/stripThink.js +50 -0
  450. package/src/web/browserBridge.js +447 -0
  451. package/src/web/protocol.js +19 -0
  452. package/workflows/adaptive-research.yaml +13 -5
  453. package/workflows/book-review-short.yaml +36 -10
  454. package/workflows/e2e-write-greet.yaml +6 -2
  455. package/workflows/illustrate.yaml +227 -0
  456. package/workflows/plan.yaml +460 -179
  457. package/workflows/ppt.yaml +1659 -0
  458. package/workflows/ralph-loop.yaml +199 -0
  459. package/workflows/schema.json +81 -23
  460. package/workflows/webppt.yaml +496 -0
  461. package/workflows/word.yaml +710 -0
  462. package/workflows/youtube-shorts.yaml +46 -15
  463. package/MINIMAL-TRACE.md +0 -77
  464. package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
  465. package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
  466. package/plugins/ralph-wiggum/README.md +0 -197
  467. package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
  468. package/plugins/ralph-wiggum/commands/help.md +0 -137
  469. package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
  470. package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
  471. package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
  472. package/plugins/ralph-wiggum/plugin.js +0 -280
  473. package/plugins/ralph-wiggum/src/goalState.js +0 -258
  474. package/plugins/ralph-wiggum/src/sentinels.js +0 -76
  475. package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
  476. package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
  477. package/plugins/workflow-runner/src/miniReAct.js +0 -223
  478. package/plugins/workflow-runner/src/voteHelpers.js +0 -110
  479. package/skills/config/SKILL.md +0 -123
  480. package/skills/frontend-design/LICENSE.txt +0 -177
  481. package/skills/frontend-design/SKILL.md +0 -42
  482. package/src/ui/ProgressPanel.js +0 -54
  483. package/src/ui/StreamingBlock.js +0 -11
  484. package/src/ui/ToolStatus.js +0 -11
@@ -0,0 +1,710 @@
1
+ name: word
2
+ description: >
3
+ 生成 Word 长文(素材驱动版,word):统一摄取用户给的 Word/PPT/PDF/Excel/图片等素材
4
+ (可已有配图,也可纯文字)+ 一句要求 → 抽取文字与客户图 → 逐图识图 → 合并成
5
+ material.md/material.json → 总结、重组、扩写成知乎深度文章风格 → 规划图文混排
6
+ (客户图必须使用,必要时图生图增强;章节需要解释性视觉时积极文生图)→
7
+ Markdown-first 写 article.md → 使用 minimal-agent 自带 docx skill 转成 Word →
8
+ OPC 校验后交付 docx。Word 是阅读型长文,不走 PPT 的 Web 页面设计、HTML deck、
9
+ 构图门、三层 hybrid 导出或固定画布视觉修复。
10
+ version: "0.1"
11
+
12
+ artifacts:
13
+ - "./out/article.docx"
14
+
15
+ self_heal:
16
+ max_retries: 2
17
+ retry_delay_ms: 20000
18
+
19
+ inputs:
20
+ - name: topic
21
+ type: string
22
+ required: true
23
+ greedy: true
24
+ description: "Word 长文主题 / 完整需求(中文自然语言即可:总结、扩写、改写、知乎长文、受众、语气、素材使用方式等)。"
25
+ - name: source
26
+ type: string
27
+ default: ""
28
+ description: "【素材文档·可选 --input】已有配图 Word、纯文字 Word、PPT、PDF、Excel、图片或混合素材路径。留空时解析 topic 中的文件线索,仍无明确素材则扫描当前目录支持格式。"
29
+ - name: out
30
+ type: string
31
+ default: "./out/article.docx"
32
+ description: "【高级·可选 --input】输出 Word 文件路径。"
33
+ - name: image_intensity
34
+ type: enum
35
+ values: ["minimal", "balanced", "rich"]
36
+ default: "balanced"
37
+ description: "【高级·可选 --input】配图积极性:minimal=只用客户图和少量必要解释图;balanced=客户图全用 + 关键章节配图;rich=客户图全用 + 所有适合视觉解释的章节积极文生图。"
38
+ - name: quality
39
+ type: enum
40
+ values: ["fast", "best"]
41
+ default: "fast"
42
+ description: "【高级·可选 --input】质量模式:fast=确定性硬门 + 一次导出;best=更严格正文/配图复核,可在后续版本扩展更多修订轮。"
43
+ - name: debug_keep_build
44
+ type: enum
45
+ values: ["true", "false"]
46
+ default: "true"
47
+ description: "【调试·可选 --input】是否保留 ./build 中间产物。默认 true,便于检查 article.md、material.json、img_plan.json 和报告。"
48
+
49
+ steps:
50
+ - id: stage0_analyze
51
+ title: "阶段1/13·需求分析与写作策略"
52
+ agent: |
53
+ 你要为用户做一篇 Word 长文。**本步只做需求分析和写作策略,不写文件、不生成 Word、不调用导出工具。**
54
+
55
+ 用户原始要求:${inputs.topic}
56
+ 素材路径:${inputs.source}
57
+ 配图积极性:${inputs.image_intensity}
58
+
59
+ 请输出简洁结论,供后续步骤引用:
60
+ - 文章目标:总结 / 扩写 / 改写 / 深度解读 / 报告化整理分别占多大比重。
61
+ - 受众和阅读场景:知乎深度文章、公众号长文、内部报告或客户材料复盘等。
62
+ - 内容深度:观点密度、解释粒度、是否需要补充背景常识。
63
+ - 写作风格:知乎深度文章,要求有观点、有论证、有转折、有小标题、有结论,不是 PPT 文案,也不是资料堆砌。
64
+ - 图文策略:
65
+ - 有客户图:所有客户图必须使用,原图或图生图增强后进入最终 Word。
66
+ - 无客户图:进入**纯 topic 创作模式**,必须基于用户要求自行总结扩写,并按章节观点生成文生图,不能交付纯文字 Word。
67
+ - 所有生图提示词必须结合上下文和章节观点,禁止空泛的“现代科技风”“知乎配图”“抽象背景”。
68
+ - 关键默认假设。
69
+ capture: writing_strategy
70
+ goal_supplement: true
71
+ onError: continue
72
+ maxTurns: 8
73
+
74
+ - id: stage_extract
75
+ title: "阶段2/13·摄取素材:抽取文字与客户图"
76
+ tool: Bash
77
+ args:
78
+ command: |
79
+ set -e
80
+ mkdir -p ./build ./out
81
+ rm -f \
82
+ ./build/article.md \
83
+ ./build/article_outline.md \
84
+ ./build/build_complete \
85
+ ./build/export-summary.md \
86
+ ./build/img_plan.json \
87
+ ./build/image_map.json \
88
+ ./build/material.md \
89
+ ./build/material.json \
90
+ ./build/source_resolution.json \
91
+ ./build/source_assets.json \
92
+ ./build/source.md \
93
+ ./build/source_stats.json \
94
+ ./build/user_request.md \
95
+ ./build/word_topic_image_gate.json \
96
+ ./build/word_topic_image_gate.md \
97
+ ./build/word_customer_image_usage.json \
98
+ ./build/word_customer_image_usage.md
99
+ rm -rf ./build/assets ./build/vision ./build/generated-image-reviews
100
+ mkdir -p ./build/assets ./build/vision
101
+
102
+ RESOLVE="skills/ui-design/scripts/resolve_source_input.py"
103
+ EXTRACT="skills/ui-design/scripts/extract_source_assets.py"
104
+ STATS="skills/image-stats/scripts/image_stats.py"
105
+ RAW_TOPIC="$(cat <<'EOF_TOPIC'
106
+ ${inputs.topic}
107
+ EOF_TOPIC
108
+ )"
109
+ RAW_SOURCE="$(cat <<'EOF_SOURCE'
110
+ ${inputs.source}
111
+ EOF_SOURCE
112
+ )"
113
+ python3 "$RESOLVE" \
114
+ --source "$RAW_SOURCE" \
115
+ --topic "$RAW_TOPIC" \
116
+ --cwd . \
117
+ --out ./build/source_resolution.json
118
+ SOURCE="$(python3 -c 'import json; data=json.load(open("./build/source_resolution.json", encoding="utf-8")); print(data.get("resolved_path") or "")')"
119
+ if [ -n "$SOURCE" ]; then
120
+ python3 "$EXTRACT" "$SOURCE" --out ./build -v
121
+ else
122
+ python3 "$EXTRACT" . --scan --out ./build -v
123
+ fi
124
+ python3 -c 'import json,sys; r=json.load(open("./build/source_resolution.json", encoding="utf-8")); a=json.load(open("./build/source_assets.json", encoding="utf-8")); ok=not (r.get("requires_source") and not a.get("has_source")); print("WORD_SOURCE_REQUIRED_BUT_EMPTY: 用户明确要求使用素材文件,但抽取结果为空。", file=sys.stderr) if not ok else None; print(json.dumps(r, ensure_ascii=False, indent=2), file=sys.stderr) if not ok else None; sys.exit(0 if ok else 3)'
125
+ python3 "$STATS" ./build/assets --scan --json > ./build/source_stats.json
126
+ cat > ./build/user_request.md <<'EOF'
127
+ # 用户原始输入与目标
128
+
129
+ - 主题/指令:${inputs.topic}
130
+ - 素材路径:${inputs.source}
131
+ - 输出文件:${inputs.out}
132
+ - 配图积极性:${inputs.image_intensity}
133
+ - 质量模式:${inputs.quality}
134
+
135
+ ## 阶段1写作策略
136
+
137
+ ${writing_strategy}
138
+
139
+ ## 执行优先级
140
+
141
+ 1. 用户原始输入和素材最高权重,后续写作、配图、导出都必须回看本文件。
142
+ 2. Word 是阅读型长文:正文主导、深度论证、图文混排,绝不按 PPT 固定画布思路写。
143
+ 3. 客户提供的图片必须全部使用:原图使用或图生图增强后使用,不能无故丢弃。
144
+ 4. 文生图只服务章节理解,不做无上下文装饰图。
145
+ EOF
146
+ echo "WORD_SOURCE_EXTRACT_READY"
147
+ test -f ./build/source_assets.json
148
+ onError: halt
149
+
150
+ - id: stage_vision_loop
151
+ title: "阶段3/13·逐图识图:客户图内容与文章落点"
152
+ when: "fileExists('./build/source_assets.json')"
153
+ type: loop
154
+ over: "${asArray(readJson('./build/source_assets.json', 'images'))}"
155
+ as: img
156
+ fresh_context: true
157
+ do:
158
+ - id: vision_one
159
+ title: "阶段3/13·识图 ${img.file}"
160
+ llm: |
161
+ 你在为 Word 长文识别客户图片。下方已附上客户图片 `${img.file}`(朝向 ${img.orient},来自素材章节「${img.section}」)。
162
+ 只输出合法 JSON 对象,不要 Markdown、不要代码围栏。字符串内部不要使用未转义英文双引号。
163
+
164
+ JSON 字段:
165
+ - `description`:图片内容,包含主体、场景、图表/截图/照片类型、可读文字或关键信息。
166
+ - `key_elements`:关键元素数组。
167
+ - `content_type`:photo|screenshot_slide|screenshot_ui|chart|diagram|document_scan|poster|other。
168
+ - `information_density`:low|medium|high。图表、截图、文档扫描通常 high。
169
+ - `suggested_article_section`:这张图最适合放入文章的哪类章节,结合素材上下文判断。
170
+ - `caption_hint`:适合 Word 图注的一句话,必须和文章观点/证据有关。
171
+ - `enhance_recommended`:true/false。低清、比例不适合、背景杂乱、风格不统一时 true;信息密集图/截图/图表若增强会损失文字则 false。
172
+ - `enhance_prompt`:如果需要图生图增强,写英文提示词;必须保留原始主体、信息语义和构图重点,只改善清晰度、比例、光线、背景整洁度和 Word 文章配图质感。
173
+ - `use_rule`:必须写明“所有客户图必须使用,原图或增强后进入最终 Word”。
174
+ images: ["./build/assets/${img.file}"]
175
+ image_detail: high
176
+ capture:
177
+ text: vision_json
178
+ onError: continue
179
+ maxTurns: 3
180
+
181
+ - id: write_vision_json
182
+ title: "阶段3/13·写入识图 JSON ${img.file}"
183
+ when: "length(vision_json) > 0"
184
+ tool: Write
185
+ args:
186
+ file_path: "./build/vision/${img.file}.json"
187
+ content: "${vision_json}"
188
+ onError: continue
189
+
190
+ - id: sanitize_vision_json
191
+ title: "阶段3/13·校验识图 JSON ${img.file}"
192
+ when: "fileExists('./build/vision/${img.file}.json')"
193
+ tool: Bash
194
+ args:
195
+ command: |
196
+ python3 - "./build/vision/${img.file}.json" <<'PYEOF'
197
+ import json, sys, os
198
+ path = sys.argv[1]
199
+ try:
200
+ data = json.load(open(path, encoding="utf-8"))
201
+ if not isinstance(data, dict):
202
+ raise ValueError("root must be object")
203
+ json.dump(data, open(path, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
204
+ except Exception as e:
205
+ print(f"WORD_VISION_JSON_INVALID {path}: {e}", file=sys.stderr)
206
+ try:
207
+ os.remove(path)
208
+ except FileNotFoundError:
209
+ pass
210
+ PYEOF
211
+ onError: continue
212
+
213
+ - id: stage_assemble_material
214
+ title: "阶段4/13·合并统一材料 material.md/json"
215
+ tool: Bash
216
+ args:
217
+ command: |
218
+ set -e
219
+ python3 - <<'PYEOF'
220
+ import json, os
221
+ from pathlib import Path
222
+
223
+ build = Path("./build")
224
+ assets = build / "assets"
225
+ vision_dir = build / "vision"
226
+
227
+ def read_json(path, default):
228
+ try:
229
+ return json.loads(Path(path).read_text(encoding="utf-8-sig"))
230
+ except Exception:
231
+ return default
232
+
233
+ source_assets = read_json(build / "source_assets.json", {})
234
+ source_stats = read_json(build / "source_stats.json", {})
235
+ source_text = (build / "source.md").read_text(encoding="utf-8") if (build / "source.md").exists() else ""
236
+ images = []
237
+ for img in source_assets.get("images") or []:
238
+ item = dict(img)
239
+ vf = vision_dir / f"{img.get('file')}.json"
240
+ item["vision"] = read_json(vf, {}) if vf.exists() else {}
241
+ images.append(item)
242
+
243
+ material = {
244
+ "user_request": {
245
+ "topic": """${inputs.topic}""",
246
+ "source": """${inputs.source}""",
247
+ "out": """${inputs.out}""",
248
+ "image_intensity": """${inputs.image_intensity}""",
249
+ "writing_strategy": """${writing_strategy}""",
250
+ },
251
+ "source_assets": source_assets,
252
+ "source_stats": source_stats,
253
+ "source_text": source_text,
254
+ "images": images,
255
+ "rules": {
256
+ "article_style": "知乎深度文章",
257
+ "customer_images": "所有客户图必须使用,原图或图生图增强后进入最终 Word。",
258
+ "new_images": "章节需要视觉解释时积极文生图,提示词必须结合上下文和章节观点。",
259
+ "not_ppt": "不做网页式固定画布设计、页面 JSON 设计稿、构图门或 PPTX 三层导出。",
260
+ },
261
+ }
262
+ (build / "material.json").write_text(json.dumps(material, ensure_ascii=False, indent=2), encoding="utf-8")
263
+
264
+ md = []
265
+ md.append("# Word 长文统一材料\n")
266
+ md.append("## 用户目标\n")
267
+ md.append(f"- 主题/指令:{material['user_request']['topic']}\n")
268
+ md.append(f"- 素材路径:{material['user_request']['source']}\n")
269
+ md.append(f"- 配图积极性:{material['user_request']['image_intensity']}\n")
270
+ md.append("\n## 写作策略\n\n")
271
+ md.append(material["user_request"]["writing_strategy"].strip() + "\n\n")
272
+ md.append("## 抽取文字\n\n")
273
+ md.append(source_text.strip() or "(未抽取到文字素材)")
274
+ md.append("\n\n## 客户图清单(必须全部使用)\n\n")
275
+ for i, img in enumerate(images, 1):
276
+ v = img.get("vision") or {}
277
+ md.append(f"### 图 {i}: {img.get('file')}\n")
278
+ md.append(f"- 章节来源:{img.get('section', '')}\n")
279
+ md.append(f"- 朝向:{img.get('orient', '')}\n")
280
+ md.append(f"- 内容类型:{v.get('content_type', '')}\n")
281
+ md.append(f"- 内容描述:{v.get('description', '')}\n")
282
+ md.append(f"- 建议文章章节:{v.get('suggested_article_section', '')}\n")
283
+ md.append(f"- 建议图注:{v.get('caption_hint', '')}\n")
284
+ md.append(f"- 是否建议增强:{v.get('enhance_recommended', '')}\n\n")
285
+ (build / "material.md").write_text("".join(md), encoding="utf-8")
286
+ print(f"WORD_MATERIAL_READY images={len(images)} chars={len(source_text)}")
287
+ PYEOF
288
+ test -f ./build/material.md
289
+ test -f ./build/material.json
290
+ onError: halt
291
+
292
+ - id: stage_outline
293
+ title: "阶段5/13·总结扩写大纲:知乎深度长文结构"
294
+ agent: |
295
+ 基于以下材料写一份 Word 长文大纲,落盘到 `./build/article_outline.md`:
296
+ - `./build/user_request.md`
297
+ - `./build/material.md`
298
+ - `./build/material.json`
299
+
300
+ 要求:
301
+ - 文章定位为**知乎深度文章**:有观点、有论证、有转折、有解释、有结论。
302
+ - 根据素材做总结、重组和扩写;不能只摘抄素材,也不能脱离素材编故事。
303
+ - 大纲必须包含:标题候选、导语角度、核心观点、章节结构、每章论点、证据/案例位置、结尾观点。
304
+ - 明确图文混排思路:每张客户图应该进入哪个章节;哪些章节需要额外文生图;为什么需要图。
305
+ - 对客户图写明:**所有客户图必须使用**,原图或图生图增强后使用。
306
+ - 需要文生图的章节,先写中文视觉意图和上下文,不要只写空泛风格词。
307
+ - 若 `material.json.images` 为空,说明没有客户图,必须进入**无客户图 / 纯 topic 创作模式**:
308
+ - 大纲必须规划至少 3 个解释型/场景型/概念型配图点。
309
+ - 每个配图点必须说明服务哪个章节观点和读者理解,不允许装饰图。
310
+ - 默认 `image_intensity=balanced` 至少 3 张;`rich` 至少 5 张;`minimal` 至少 1 张封面或核心概念图。
311
+
312
+ 写完后简短汇报。
313
+ done_when: "fileExists('./build/article_outline.md')"
314
+ onError: halt
315
+ maxTurns: 18
316
+
317
+ - id: stage_write_article
318
+ title: "阶段6/13·写作 article.md:知乎深度长文正文"
319
+ agent: |
320
+ 基于 `./build/article_outline.md`、`./build/material.md`、`./build/material.json` 写正文,落盘到 `./build/article.md`。
321
+
322
+ 写作要求:
323
+ - 风格是**知乎深度文章**,不是 PPT 文案,不是资料堆砌。
324
+ - 要有清晰标题、导语、多个二级/三级标题、论证段、解释段、案例段、结论。
325
+ - 允许总结扩写,但必须结合素材上下文和用户目标;不要一知半解地泛泛发挥。
326
+ - 先用 Markdown 占位标记图片,例如:
327
+ `<!-- image: src_1.png | purpose: 证明某观点 | caption: ... -->`
328
+ - 每张客户图必须至少有一个占位。
329
+ - **无客户图 / 纯 topic 创作模式**也必须保留文生图占位,不能交付纯文字 Word:
330
+ - `minimal` 至少 1 个封面/核心概念图占位。
331
+ - `balanced` 至少 3 个图片占位。
332
+ - `rich` 至少 5 个图片占位。
333
+ - 每个占位必须贴近对应章节观点,写清 purpose 和 caption。
334
+ - 图片附近必须有上下文解释,不能把图片孤零零塞进去。
335
+ - 文章中避免出现“作为 AI”“根据材料可知”这类过程话。
336
+ done_when: "fileExists('./build/article.md')"
337
+ onError: halt
338
+ maxTurns: 25
339
+
340
+ - id: stage_img_plan
341
+ title: "阶段7/13·图文混排计划 img_plan/image_map"
342
+ agent: |
343
+ 基于 `./build/article.md`、`./build/material.json`、`./build/material.md` 生成两个文件:
344
+ 1. `./build/img_plan.json`
345
+ 2. `./build/image_map.json`
346
+
347
+ `img_plan.json` 是给 GenerateImage 工具使用的数组,只放需要实际生成/增强的图:
348
+ - 文生图:`{"file":"word_img_1.png","mode":"text-to-image","aspect":"16:9","prompt":"..."}`
349
+ - 图生图:`{"file":"enhanced_src_1.png","mode":"image-to-image","source_file":"src_1.png","aspect":"4:3","prompt":"..."}`
350
+ - prompt 必须是英文,但必须来自文章上下文、章节观点和 material.md,不允许空泛的“现代科技风”“知乎配图”“抽象背景”。
351
+
352
+ `image_map.json` 记录所有最终要进入 Word 的图片,数组字段至少包含:
353
+ - `source_file`:客户图原文件;文生图可为空字符串。
354
+ - `final_file`:最终插入 article.md 的图片文件名。客户图原图可直接是 `src_K.png`;增强图是 `enhanced_src_K.png`;文生图是 `word_img_K.png`。
355
+ - `article_section`:插入章节。
356
+ - `caption`:Word 图注。
357
+ - `alt`:图片 alt 文本。
358
+ - `usage`:source-original|source-enhanced|text-to-image。
359
+ - `context_reason`:为什么这张图服务该章节论点。
360
+
361
+ 硬性规则:
362
+ - `material.json` 的 `images` 里所有客户图都必须出现在 `image_map.json`,所有客户图必须使用。
363
+ - 信息密集图、截图、图表类默认 source-original 或轻增强后完整展示;不要图生图导致文字/信息丢失。
364
+ - 低清、比例不合适、背景杂乱、风格不统一的客户图可 source-enhanced,但必须保留原图主体和语义。
365
+ - 无客户图 / 纯 topic 创作模式时,`img_plan.json` 不得为空,必须全部是 `text-to-image` 文生图条目,并按 `${inputs.image_intensity}` 控制最低数量:
366
+ - `minimal`:至少 1 张。
367
+ - `balanced`:至少 3 张。
368
+ - `rich`:至少 5 张。
369
+ - 纯 topic 模式每条文生图必须包含 `file`、`mode`、`aspect`、`prompt`,其中 `mode` 必须是 `text-to-image`。
370
+ - 纯 topic 模式每条 prompt 必须结合 `article.md` 的章节观点、上下文、场景和图注意图,不允许只写风格词。
371
+ - 有客户图时也可以按 `${inputs.image_intensity}` 给关键章节补充文生图,但不能替代客户图使用。
372
+
373
+ 写完两个 JSON 后简短汇报。
374
+ done_when: "fileExists('./build/img_plan.json') && fileExists('./build/image_map.json')"
375
+ onError: halt
376
+ maxTurns: 18
377
+
378
+ - id: stage_sanitize_img_plan
379
+ title: "阶段7/13·校验配图计划 JSON"
380
+ tool: Bash
381
+ args:
382
+ command: |
383
+ set -e
384
+ python3 - <<'PYEOF'
385
+ import json, sys
386
+ from pathlib import Path
387
+ build = Path("./build")
388
+ for name, expect_array in [("img_plan.json", True), ("image_map.json", True)]:
389
+ path = build / name
390
+ data = json.loads(path.read_text(encoding="utf-8-sig"))
391
+ if expect_array and not isinstance(data, list):
392
+ raise SystemExit(f"{name} root must be array")
393
+ path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
394
+ print("WORD_IMAGE_PLAN_JSON_OK")
395
+ PYEOF
396
+ onError: halt
397
+
398
+ - id: stage_gen_images
399
+ title: "阶段8/13·客户图增强与章节配图生成"
400
+ when: "fileExists('./build/img_plan.json')"
401
+ tool: GenerateImage
402
+ args:
403
+ plan: ./build/img_plan.json
404
+ assets: ./build/assets
405
+ size: 2k
406
+ timeout_ms: 300000
407
+ wall_budget_ms: 3600000
408
+ concurrency: 2
409
+ onError: continue
410
+ max_retries: 1
411
+
412
+ - id: stage_image_quality_gate
413
+ title: "阶段8/13·补生成降级配图"
414
+ when: "fileExists('./build/image_generation_report.json')"
415
+ tool: GenerateImage
416
+ args:
417
+ plan: ./build/img_plan.json
418
+ assets: ./build/assets
419
+ size: 2k
420
+ timeout_ms: 300000
421
+ wall_budget_ms: 3600000
422
+ retry_degraded_report: ./build/image_generation_report.json
423
+ max_rounds: 1
424
+ concurrency: 2
425
+ onError: continue
426
+ max_retries: 1
427
+
428
+ - id: stage_generated_image_gate
429
+ title: "阶段8/13·配图成品硬闸门"
430
+ when: "fileExists('./build/image_generation_report.json')"
431
+ tool: Bash
432
+ args:
433
+ command: |
434
+ set -e
435
+ python3 - <<'PYEOF'
436
+ import json
437
+ from pathlib import Path
438
+
439
+ build = Path("./build")
440
+ report = json.loads((build / "image_generation_report.json").read_text(encoding="utf-8"))
441
+ plan = json.loads((build / "img_plan.json").read_text(encoding="utf-8"))
442
+ assets = build / "assets"
443
+ errors = []
444
+ if report.get("qualityOk") is not True:
445
+ errors.append("image generation report is degraded or incomplete")
446
+ for item in plan:
447
+ name = str(item.get("file") or "")
448
+ path = assets / name
449
+ if not name or not path.is_file():
450
+ errors.append(f"missing generated image: {name or '<unnamed>'}")
451
+ elif path.stat().st_size < 8192:
452
+ errors.append(f"generated image is implausibly small: {name} ({path.stat().st_size} bytes)")
453
+ if errors:
454
+ raise SystemExit("WORD_GENERATED_IMAGE_GATE_FAILED: " + "; ".join(errors))
455
+ print("WORD_GENERATED_IMAGE_GATE_OK")
456
+ PYEOF
457
+ onError: halt
458
+
459
+ - id: stage_finalize_markdown
460
+ title: "阶段9/13·Markdown 图文混排收口"
461
+ agent: |
462
+ 更新 `./build/article.md`,把 `./build/image_map.json` 中的图片按章节插入最终位置。
463
+
464
+ 要求:
465
+ - 图片路径统一使用 `./build/assets/<final_file>`。
466
+ - 每张图必须有 Markdown 图片语法和紧随其后的图注,例如:
467
+ `![alt](./build/assets/final.png)`
468
+ `*图:caption*`
469
+ - 删除临时 `<!-- image: ... -->` 占位。
470
+ - 保持知乎深度文章风格:图片前后要有解释段,说明它支持了哪个观点或案例。
471
+ - 统一标题层级、段落节奏、引用块、表格、结论。
472
+ - 不要加入 PPT 术语,不要提网页 deck、页面 JSON 设计稿、构图门或 fixed canvas。
473
+ done_when: "fileExists('./build/article.md')"
474
+ onError: halt
475
+ maxTurns: 18
476
+
477
+ - id: stage_topic_image_gate
478
+ title: "阶段10/13·纯 topic 文生图闸门"
479
+ tool: Bash
480
+ args:
481
+ command: |
482
+ set -e
483
+ python3 - <<'PYEOF'
484
+ import json, sys
485
+ from pathlib import Path
486
+
487
+ build = Path("./build")
488
+ material = json.loads((build / "material.json").read_text(encoding="utf-8"))
489
+ customer = [img.get("file") for img in material.get("images", []) if img.get("file")]
490
+ if customer:
491
+ print("WORD_TOPIC_IMAGE_GATE_SKIP: 有客户图,交给客户图用尽闸门")
492
+ raise SystemExit(0)
493
+
494
+ intensity = "${inputs.image_intensity}"
495
+ required = {"minimal": 1, "balanced": 3, "rich": 5}.get(intensity, 3)
496
+ img_plan = json.loads((build / "img_plan.json").read_text(encoding="utf-8"))
497
+ image_map = json.loads((build / "image_map.json").read_text(encoding="utf-8"))
498
+ article = (build / "article.md").read_text(encoding="utf-8")
499
+
500
+ errors = []
501
+ if not isinstance(img_plan, list):
502
+ errors.append("img_plan.json root must be array")
503
+ img_plan = []
504
+ if not isinstance(image_map, list):
505
+ errors.append("image_map.json root must be array")
506
+ image_map = []
507
+
508
+ text_to_image = []
509
+ for i, item in enumerate(img_plan):
510
+ if not isinstance(item, dict):
511
+ errors.append(f"img_plan[{i}] must be object")
512
+ continue
513
+ if item.get("mode") != "text-to-image":
514
+ errors.append(f"img_plan[{i}].mode must be text-to-image in pure topic mode")
515
+ for key in ("file", "mode", "aspect", "prompt"):
516
+ if not str(item.get(key) or "").strip():
517
+ errors.append(f"img_plan[{i}].{key} required")
518
+ if item.get("mode") == "text-to-image":
519
+ text_to_image.append(item)
520
+
521
+ if len(text_to_image) < required:
522
+ errors.append(
523
+ f"pure topic mode requires at least {required} text-to-image items for image_intensity={intensity}, got {len(text_to_image)}"
524
+ )
525
+
526
+ mapped_text_images = [m for m in image_map if isinstance(m, dict) and m.get("usage") == "text-to-image"]
527
+ if len(mapped_text_images) < required:
528
+ errors.append(f"image_map requires at least {required} text-to-image entries, got {len(mapped_text_images)}")
529
+ for i, item in enumerate(mapped_text_images):
530
+ for key in ("final_file", "article_section", "caption", "alt", "context_reason"):
531
+ if not str(item.get(key) or "").strip():
532
+ errors.append(f"image_map text-to-image entry {i}.{key} required")
533
+ final_file = str(item.get("final_file") or "")
534
+ if final_file and final_file not in article:
535
+ errors.append(f"article.md does not reference text-to-image final_file: {final_file}")
536
+
537
+ report = {
538
+ "ok": not errors,
539
+ "mode": "pure-topic",
540
+ "image_intensity": intensity,
541
+ "required_text_to_image": required,
542
+ "img_plan_text_to_image": len(text_to_image),
543
+ "image_map_text_to_image": len(mapped_text_images),
544
+ "errors": errors,
545
+ }
546
+ (build / "word_topic_image_gate.json").write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
547
+ md = ["# Word 纯 topic 文生图闸门\n\n", f"- 模式:无客户图 / 纯 topic\n", f"- 配图强度:{intensity}\n", f"- 最低文生图数量:{required}\n", f"- 结果:{'通过' if not errors else '失败'}\n"]
548
+ for e in errors:
549
+ md.append(f"- {e}\n")
550
+ (build / "word_topic_image_gate.md").write_text("".join(md), encoding="utf-8")
551
+ if errors:
552
+ print(json.dumps(report, ensure_ascii=False, indent=2), file=sys.stderr)
553
+ raise SystemExit("WORD_TOPIC_IMAGE_GATE_FAILED: 纯 topic 模式必须生成足量文生图并完成 article.md 引用")
554
+ print("WORD_TOPIC_IMAGE_GATE_OK")
555
+ PYEOF
556
+ onError: halt
557
+
558
+ - id: stage_customer_image_gate
559
+ title: "阶段10/13·客户图用尽闸门"
560
+ tool: Bash
561
+ args:
562
+ command: |
563
+ set -e
564
+ python3 - <<'PYEOF'
565
+ import json, re, sys
566
+ from pathlib import Path
567
+
568
+ build = Path("./build")
569
+ material = json.loads((build / "material.json").read_text(encoding="utf-8"))
570
+ image_map = json.loads((build / "image_map.json").read_text(encoding="utf-8"))
571
+ article = (build / "article.md").read_text(encoding="utf-8")
572
+ customer = [img.get("file") for img in material.get("images", []) if img.get("file")]
573
+ mapped = {m.get("source_file") for m in image_map if m.get("source_file")}
574
+ text = article
575
+ missing = []
576
+ for src in customer:
577
+ finals = [m.get("final_file") for m in image_map if m.get("source_file") == src]
578
+ if src not in mapped:
579
+ missing.append({"source_file": src, "reason": "not in image_map.source_file"})
580
+ continue
581
+ if not any(f and f in text for f in finals):
582
+ missing.append({"source_file": src, "reason": "mapped but final_file not referenced in article.md", "final_files": finals})
583
+ report = {"ok": not missing, "customer_count": len(customer), "missing": missing}
584
+ (build / "word_customer_image_usage.json").write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
585
+ md = ["# Word 客户图用尽闸门\n\n", f"- 客户图数量:{len(customer)}\n", f"- 结果:{'通过' if not missing else '失败'}\n"]
586
+ for item in missing:
587
+ md.append(f"- 缺失:{item}\n")
588
+ (build / "word_customer_image_usage.md").write_text("".join(md), encoding="utf-8")
589
+ if missing:
590
+ print(json.dumps(report, ensure_ascii=False, indent=2), file=sys.stderr)
591
+ raise SystemExit("WORD_CUSTOMER_IMAGE_USAGE_FAILED: 所有客户图必须使用,缺失项见 build/word_customer_image_usage.md")
592
+ print("WORD_CUSTOMER_IMAGE_USAGE_OK")
593
+ PYEOF
594
+ onError: halt
595
+
596
+ - id: stage_export_docx
597
+ title: "阶段11/13·使用 docx skill 导出 Word"
598
+ skill: docx
599
+ input: |
600
+ 本步骤是 `skill: docx` 必要节点。
601
+ 请严格按当前 minimal-agent 自带 `skills/docx/SKILL.md` 的指引,把 `./build/article.md` 转换为 Word 文件 `${inputs.out}`。
602
+
603
+ 硬性要求:
604
+ - 优先使用 Markdown-first 路线:pandoc `./build/article.md -f markdown-implicit_figures -t docx -o ${inputs.out} --wrap=preserve --standalone`。
605
+ - 必须关闭 pandoc implicit_figures,避免 Markdown 图片 alt 文本被渲染成额外可见图注;最终只保留 article.md 中显式的 `*图:...*` 图注。
606
+ - 如果 pandoc 不可用或图片/表格转换失败,按 docx skill 指引回退到 python-docx 或 docx-js。
607
+ - 若使用 docx-js,必须用 Node 运行脚本,不要用 Bun。
608
+ - 保留 Markdown 标题层级、列表、表格、引用块、图片、图注和正文段落。
609
+ - 图片来自 `./build/assets/<final_file>`,不要丢图。
610
+ - 最终必须生成 `${inputs.out}`。
611
+ onError: halt
612
+ maxTurns: 25
613
+
614
+ - id: stage_verify_docx
615
+ title: "阶段12/13·DOCX OPC 校验"
616
+ tool: Bash
617
+ args:
618
+ command: |
619
+ set -e
620
+ OUT="${inputs.out}"
621
+ test -f "$OUT"
622
+ python3 - "$OUT" <<'PYEOF'
623
+ import shutil, sys, tempfile, zipfile
624
+ from pathlib import Path
625
+ from xml.etree import ElementTree as ET
626
+
627
+ path = Path(sys.argv[1])
628
+ ns = "http://schemas.openxmlformats.org/package/2006/content-types"
629
+ ET.register_namespace("", ns)
630
+
631
+ with zipfile.ZipFile(path, "r") as zin:
632
+ names = zin.namelist()
633
+ has_png = any(n.startswith("word/media/") and n.lower().endswith(".png") for n in names)
634
+ content_types = zin.read("[Content_Types].xml")
635
+
636
+ if has_png:
637
+ root = ET.fromstring(content_types)
638
+ has_default = any(
639
+ child.tag == f"{{{ns}}}Default"
640
+ and child.attrib.get("Extension", "").lower() == "png"
641
+ for child in root
642
+ )
643
+ if not has_default:
644
+ ET.SubElement(root, f"{{{ns}}}Default", {"Extension": "png", "ContentType": "image/png"})
645
+ updated = ET.tostring(root, encoding="utf-8", xml_declaration=True)
646
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as tmp:
647
+ tmp_path = Path(tmp.name)
648
+ with zipfile.ZipFile(path, "r") as zin, zipfile.ZipFile(tmp_path, "w", zipfile.ZIP_DEFLATED) as zout:
649
+ for item in zin.infolist():
650
+ if item.filename == "[Content_Types].xml":
651
+ zout.writestr(item, updated)
652
+ else:
653
+ zout.writestr(item, zin.read(item.filename))
654
+ shutil.move(tmp_path, path)
655
+ print("WORD_DOCX_PNG_CONTENT_TYPE_ADDED")
656
+ PYEOF
657
+ python3 skills/docx/scripts/opc_check.py "$OUT" || (
658
+ python3 skills/docx/scripts/opc_check.py "$OUT" --repack "$OUT.tmp.docx" &&
659
+ mv -f "$OUT.tmp.docx" "$OUT" &&
660
+ python3 skills/docx/scripts/opc_check.py "$OUT"
661
+ )
662
+ python3 skills/docx/scripts/office/validate.py "$OUT" || true
663
+ python3 - <<'PYEOF'
664
+ import json, os
665
+ from pathlib import Path
666
+ build = Path("./build")
667
+ article = build / "article.md"
668
+ image_map = json.loads((build / "image_map.json").read_text(encoding="utf-8")) if (build / "image_map.json").exists() else []
669
+ usage = json.loads((build / "word_customer_image_usage.json").read_text(encoding="utf-8")) if (build / "word_customer_image_usage.json").exists() else {}
670
+ summary = [
671
+ "# Word 导出摘要\n\n",
672
+ f"- 输出文件:${inputs.out}\n",
673
+ f"- Markdown:./build/article.md\n",
674
+ f"- 文章字符数:{len(article.read_text(encoding='utf-8')) if article.exists() else 0}\n",
675
+ f"- 图片映射数量:{len(image_map)}\n",
676
+ f"- 客户图数量:{usage.get('customer_count', 0)}\n",
677
+ "- OPC 校验:通过\n",
678
+ ]
679
+ (build / "export-summary.md").write_text("".join(summary), encoding="utf-8")
680
+ print("WORD_DOCX_VERIFY_OK")
681
+ PYEOF
682
+ touch ./build/build_complete
683
+ onError: halt
684
+
685
+ - id: cleanup_intermediates
686
+ title: "阶段13/13·处理中间产物"
687
+ when: "inputs.debug_keep_build == 'false'"
688
+ tool: Bash
689
+ args:
690
+ command: |
691
+ set -e
692
+ mkdir -p ./out
693
+ cp ./build/export-summary.md ./out/word-export-summary.md 2>/dev/null || true
694
+ rm -rf ./build
695
+ echo "WORD_BUILD_CLEANED"
696
+ onError: continue
697
+
698
+ - id: final_report
699
+ title: "阶段13/13·完成报告"
700
+ type: echo
701
+ message: |
702
+ Word 长文已生成。
703
+
704
+ - 输出 Word:${inputs.out}
705
+ - Markdown 草稿:./build/article.md
706
+ - 统一材料:./build/material.md / ./build/material.json
707
+ - 配图计划:./build/img_plan.json / ./build/image_map.json
708
+ - 导出摘要:./build/export-summary.md
709
+
710
+ 流程:素材摄取 → 逐图识图 → 统一 material → 知乎深度文章大纲 → article.md 正文 → 图文混排计划 → 客户图增强/章节配图 → 客户图用尽闸门 → docx skill 导出 → OPC 校验。