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,251 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ check_ui_artifact_pptx_test.py —— 锁定「--for-pptx-export 不再为 web-app 件报 warning」。
5
+
6
+ 根因:导出 PPTX 的 deck 是**静态导出目标**——导出脚本自己控制每页 hidden、强制 1920×1080。
7
+ 但 check_ui_artifact 原本会对它报「缺 Tweaks / 缺 localStorage 持久化 / 缺 viewport 缩放」等
8
+ warning,诱导弱模型去补 EDITMODE/localStorage/scale 而非修构图。本测试钉死:
9
+ - for_pptx_export=True:纯静态 deck **不**报这些 web-app warning,但**仍**报三层标注类提示(导出相关)。
10
+ - for_pptx_export=False(web 路径):这些 warning **照常**报(不回归 web 行为)。
11
+
12
+ 运行:python skills/ui-design/scripts/check_ui_artifact_pptx_test.py
13
+ """
14
+
15
+ import os
16
+ import sys
17
+ import tempfile
18
+ import unittest
19
+ from pathlib import Path
20
+
21
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
22
+ from check_ui_artifact import run_checks # noqa: E402
23
+
24
+ # 渐变压图反模式:.edit-bg 把不透明渐变写在逗号 url() **之前** → 渐变画在图上面、盖死 AI 背景图。
25
+ GRADIENT_OVER_IMAGE_DECK = """<!doctype html>
26
+ <html lang="zh-CN">
27
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>渐变压图</title>
28
+ <style>
29
+ .slide{display:grid}[hidden]{display:none!important}
30
+ .edit-bg{position:absolute;inset:0;background:linear-gradient(135deg,#0a1020 0%,#0a1020 100%),url('assets/hero.png');background-size:cover}
31
+ </style></head>
32
+ <body>
33
+ <section class="slide" data-screen-label="01 封面"><div class="edit-bg"></div><h1 data-pptx-kind="text">标题</h1></section>
34
+ </body></html>
35
+ """
36
+
37
+ GRADIENT_WARNING_NEEDLE = "盖死背景图"
38
+
39
+ # 纯静态 deck:grid 排版、中文 label、三层标注齐全;**无** Tweaks/localStorage/scale JS(导出不需要)。
40
+ STATIC_DECK = """<!doctype html>
41
+ <html lang="zh-CN">
42
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>技术栈</title>
43
+ <style>.slide{display:grid;padding:86px 104px}[hidden]{display:none!important}</style></head>
44
+ <body>
45
+ <section class="slide cards" data-screen-label="01 标题页">
46
+ <h1 data-pptx-kind="text">AI 生成 PPT 技术栈</h1>
47
+ <div data-pptx-layer="foreground"><span data-pptx-kind="text">卡片</span></div>
48
+ <div data-pptx-export="ignore"></div>
49
+ </section>
50
+ </body></html>
51
+ """
52
+
53
+ WEB_APP_NOISE = (
54
+ "Tweaks", # check_tweaks
55
+ "persist current slide", # localStorage 持久化
56
+ "viewport scaling", # transform: scale
57
+ "transform-origin", # transform-origin
58
+ )
59
+
60
+ MALFORMED_VISIBLE_CSS = """<!doctype html>
61
+ <html lang="zh-CN">
62
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>坏样例</title>
63
+ <style>.slide{display:grid}[hidden]{display:none!important}</style></head>
64
+ <body>
65
+ <section class="slide" data-screen-label="01 标题页"><h1>标题</h1></section>
66
+ /* ============================================================
67
+ 这段 CSS 错误地裸露在 body 里
68
+ ============================================================ */
69
+ .slide.p2 {
70
+ display: grid;
71
+ }
72
+ <section class="slide p2" data-screen-label="02 第二页"><h1>第二页</h1></section>
73
+ </body></html>
74
+ """
75
+
76
+ DUPLICATE_BODY = """<!doctype html>
77
+ <html lang="zh-CN">
78
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>坏样例</title>
79
+ <style>.slide{display:grid}[hidden]{display:none!important}</style></head>
80
+ <body><section class="slide" data-screen-label="01 标题页"><h1>标题</h1></section></body>
81
+ <body><section class="slide" data-screen-label="02 第二页"><h1>第二页</h1></section></body>
82
+ </html>
83
+ """
84
+
85
+
86
+ # ── AI 味确定性 WARNING(F2):禁栈字体 + 左边框强调卡 ──
87
+ OVERUSED_FONT_NEEDLE = "Overused font family"
88
+ LEFT_BORDER_NEEDLE = "Left-border accent card"
89
+
90
+ # 主字体 = Inter → 触发(模板味)。
91
+ OVERUSED_FONT_HTML = """<!doctype html>
92
+ <html lang="zh-CN">
93
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>字体</title>
94
+ <style>:root{font-family:"Inter","PingFang SC",sans-serif}h1{color:#111}</style></head>
95
+ <body><main data-screen-label="01 网页"><h1>标题</h1></main></body></html>
96
+ """
97
+
98
+ # CJK 栈:PingFang 首位、Arial/Helvetica 仅末位兜底 → **不**触发(合法实践,防误报)。
99
+ CJK_FALLBACK_HTML = """<!doctype html>
100
+ <html lang="zh-CN">
101
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>字体</title>
102
+ <style>:root{font-family:"PingFang SC","Microsoft YaHei","Noto Sans CJK SC","Helvetica Neue",Helvetica,Arial,sans-serif}</style></head>
103
+ <body><main data-screen-label="01 网页"><h1>标题</h1></main></body></html>
104
+ """
105
+
106
+ # 左边框 <4px solid> + 圆角,同一规则块 → 触发(经典 AI 味强调卡)。
107
+ LEFT_BORDER_CARD_HTML = """<!doctype html>
108
+ <html lang="zh-CN">
109
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>卡</title>
110
+ <style>.note{border-left:4px solid #2f80ed;border-radius:8px;padding:16px}</style></head>
111
+ <body><main data-screen-label="01 网页"><div class="note">提示</div></main></body></html>
112
+ """
113
+
114
+ # 普通左边框、**无** border-radius → **不**触发(非圆角强调卡,避免误伤分隔线等正当用法)。
115
+ PLAIN_LEFT_BORDER_HTML = """<!doctype html>
116
+ <html lang="zh-CN">
117
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>线</title>
118
+ <style>.quote{border-left:4px solid #ccc;padding-left:12px}</style></head>
119
+ <body><main data-screen-label="01 网页"><blockquote class="quote">引用</blockquote></main></body></html>
120
+ """
121
+
122
+
123
+ class CheckUiArtifactPptxTest(unittest.TestCase):
124
+ def setUp(self):
125
+ fd, self.path = tempfile.mkstemp(suffix=".html")
126
+ os.close(fd)
127
+ Path(self.path).write_text(STATIC_DECK, encoding="utf-8")
128
+
129
+ def tearDown(self):
130
+ try:
131
+ os.remove(self.path)
132
+ except OSError:
133
+ pass
134
+
135
+ def _messages(self, for_pptx_export):
136
+ return [f.message for f in run_checks(Path(self.path), for_pptx_export=for_pptx_export)]
137
+
138
+ def test_pptx_export_suppresses_webapp_warnings(self):
139
+ msgs = self._messages(for_pptx_export=True)
140
+ for noise in WEB_APP_NOISE:
141
+ self.assertFalse(
142
+ any(noise in m for m in msgs),
143
+ f"--for-pptx-export 不该报 web-app warning「{noise}」,但报了:{[m for m in msgs if noise in m]}",
144
+ )
145
+
146
+ def test_web_path_still_warns_about_deck_runtime(self):
147
+ # web 路径(不导出 PPTX)仍应提示 deck 运行态能力;Tweaks 现在改为按需强制,不再默认报警。
148
+ msgs = self._messages(for_pptx_export=False)
149
+ self.assertTrue(any("persist current slide" in m for m in msgs), msgs)
150
+ self.assertTrue(any("viewport scaling" in m for m in msgs), msgs)
151
+ self.assertTrue(any("transform-origin" in m for m in msgs), msgs)
152
+
153
+ def test_pptx_export_keeps_layer_hints(self):
154
+ # 导出相关的三层标注提示仍要在(这次缺 data-pptx-export 控件之外都标了,故主要确认不误杀 export hints 流程)。
155
+ msgs = self._messages(for_pptx_export=True)
156
+ # 不应把「基础结构 OK」也吞掉——至少能跑完、返回 list。
157
+ self.assertIsInstance(msgs, list)
158
+
159
+ def test_malformed_visible_css_is_error(self):
160
+ Path(self.path).write_text(MALFORMED_VISIBLE_CSS, encoding="utf-8")
161
+ msgs = self._messages(for_pptx_export=True)
162
+ self.assertTrue(any("CSS comment block appears outside <style>" in m for m in msgs), msgs)
163
+ self.assertTrue(any("CSS selector appears outside <style>" in m for m in msgs), msgs)
164
+
165
+ def test_duplicate_body_is_error(self):
166
+ Path(self.path).write_text(DUPLICATE_BODY, encoding="utf-8")
167
+ msgs = self._messages(for_pptx_export=True)
168
+ self.assertTrue(any("Multiple <body>" in m for m in msgs), msgs)
169
+
170
+ def test_gradient_over_image_warns_in_pptx_export(self):
171
+ # --for-pptx-export 下:渐变写在 url 图之前 → 报 WARNING(含命中片段),但**不**升级为 error、不阻断导出。
172
+ Path(self.path).write_text(GRADIENT_OVER_IMAGE_DECK, encoding="utf-8")
173
+ findings = run_checks(Path(self.path), for_pptx_export=True)
174
+ msgs = [f.message for f in findings]
175
+ hits = [f for f in findings if GRADIENT_WARNING_NEEDLE in f.message]
176
+ self.assertTrue(hits, f"应报渐变压图 WARNING,实得:{msgs}")
177
+ # 命中片段要带进消息,便于定位。
178
+ self.assertTrue(any("url(" in f.message for f in hits), msgs)
179
+ # 严格 WARNING 级——不得是 error(不改变 exit code / 不阻断导出)。
180
+ for f in hits:
181
+ self.assertEqual(f.severity, "warning", f"渐变压图应为 warning,实得 {f.severity}")
182
+ # 这份 deck 结构合法,除该 warning 外不应有任何 error → main() 退出码维持 0(不阻断)。
183
+ self.assertFalse(
184
+ [f for f in findings if f.severity == "error"],
185
+ f"渐变压图检查不该引入 error:{[f.message for f in findings if f.severity == 'error']}",
186
+ )
187
+
188
+ def test_gradient_over_image_not_reported_on_web_path(self):
189
+ # 仅 --for-pptx-export 模式扫描;web 路径(for_pptx_export=False)不报该 WARNING。
190
+ Path(self.path).write_text(GRADIENT_OVER_IMAGE_DECK, encoding="utf-8")
191
+ msgs = self._messages(for_pptx_export=False)
192
+ self.assertFalse(
193
+ any(GRADIENT_WARNING_NEEDLE in m for m in msgs),
194
+ f"web 路径不该报渐变压图 WARNING,实得:{[m for m in msgs if GRADIENT_WARNING_NEEDLE in m]}",
195
+ )
196
+
197
+
198
+ # ── F2:禁栈字体 + 左边框强调卡(确定性 WARNING,正/反例)──
199
+ def _write_and_check(self, html, for_pptx_export=False):
200
+ Path(self.path).write_text(html, encoding="utf-8")
201
+ return run_checks(Path(self.path), for_pptx_export=for_pptx_export)
202
+
203
+ def test_overused_primary_font_warns(self):
204
+ findings = self._write_and_check(OVERUSED_FONT_HTML)
205
+ hits = [f for f in findings if OVERUSED_FONT_NEEDLE in f.message]
206
+ self.assertTrue(hits, [f.message for f in findings])
207
+ for f in hits:
208
+ self.assertEqual(f.severity, "warning", f"应为 warning,实得 {f.severity}")
209
+
210
+ def test_cjk_fallback_font_not_flagged(self):
211
+ # 末位 Arial/Helvetica 兜底是合法 CJK 实践 → 不得误报(即便禁栈含 arial,只判首位)。
212
+ findings = self._write_and_check(CJK_FALLBACK_HTML)
213
+ self.assertFalse(
214
+ any(OVERUSED_FONT_NEEDLE in f.message for f in findings),
215
+ [f.message for f in findings if OVERUSED_FONT_NEEDLE in f.message],
216
+ )
217
+
218
+ def test_arial_as_primary_font_warns(self):
219
+ # `font-family: Arial, sans-serif` 当主字体 = claude_design.md:255 点名禁 → WARNING(首位命中)。
220
+ html = OVERUSED_FONT_HTML.replace('"Inter","PingFang SC",sans-serif', "Arial, sans-serif")
221
+ findings = self._write_and_check(html)
222
+ hits = [f for f in findings if OVERUSED_FONT_NEEDLE in f.message]
223
+ self.assertTrue(hits, [f.message for f in findings])
224
+ for f in hits:
225
+ self.assertEqual(f.severity, "warning", f"应为 warning,实得 {f.severity}")
226
+
227
+ def test_left_border_accent_card_warns(self):
228
+ findings = self._write_and_check(LEFT_BORDER_CARD_HTML)
229
+ hits = [f for f in findings if LEFT_BORDER_NEEDLE in f.message]
230
+ self.assertTrue(hits, [f.message for f in findings])
231
+ for f in hits:
232
+ self.assertEqual(f.severity, "warning", f"应为 warning,实得 {f.severity}")
233
+
234
+ def test_plain_left_border_not_flagged(self):
235
+ # 无圆角的普通左边框(引用条/分隔)不是强调卡 → 不得误报。
236
+ findings = self._write_and_check(PLAIN_LEFT_BORDER_HTML)
237
+ self.assertFalse(
238
+ any(LEFT_BORDER_NEEDLE in f.message for f in findings),
239
+ [f.message for f in findings if LEFT_BORDER_NEEDLE in f.message],
240
+ )
241
+
242
+ def test_new_style_checks_are_exit_code_neutral(self):
243
+ # 两条新检查全为 WARNING,绝不引入 error(共享脚本对 webppt 的 pass/fail 契约不变)。
244
+ for html in (OVERUSED_FONT_HTML, LEFT_BORDER_CARD_HTML):
245
+ findings = self._write_and_check(html)
246
+ errors = [f for f in findings if f.severity == "error"]
247
+ self.assertFalse(errors, f"新检查不该引入 error:{[f.message for f in errors]}")
248
+
249
+
250
+ if __name__ == "__main__":
251
+ unittest.main(verbosity=2)
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ deck_pages_check.py —— 分批生成 deck 的「页数完成度」确定性闸门(仅标准库)。
5
+
6
+ 为什么需要
7
+ ==========
8
+ webppt 工作流把大 deck(几十页)**分批生成**(每轮 agent 写 ≤5 页),避免单步一次写完
9
+ 几十页撞 maxTurns 烂尾(真实事故:「50 页做了 5 页就停」)。但工作流表达式引擎**读不了
10
+ 磁盘 JSON**,无法直接比较「design 规划了几页 vs deck 已生成几页」。本脚本把这个确定性比较
11
+ 放进脚本:读 design.json 的页数 + 数 deck.html 的 <section class="slide">,输出 COMPLETE /
12
+ MISSING,供分批 loop 的 branch 收口(includes(out,'COMPLETE') → break)+ 导出前兜底 verify。
13
+
14
+ 输出(供工作流 includes() 判断 + 退出码兜底)
15
+ COMPLETE: N/N 页已生成 (exit 0)
16
+ MISSING: 6,7,8(已生成 5/12 页) (exit 1)
17
+ ERROR ...(design.json 缺失/损坏) (exit 2)
18
+
19
+ 页号来源:deck.html 的 data-screen-label="NN ..." 前缀(乱序生成也能精确 diff 出缺页);
20
+ 无 label 时回退按 <section class="slide"> 数量当「已生成前 N 页」。
21
+
22
+ 用法
23
+ python deck_pages_check.py <deck.html> --design <design.json>
24
+ python deck_pages_check.py <workdir> # 目录:自动找 deck.html + design.json
25
+ """
26
+
27
+ import argparse
28
+ import json
29
+ import os
30
+ import re
31
+ import sys
32
+
33
+
34
+ def count_sections(html: str) -> int:
35
+ """数 <section ... class="...slide..."> 的数量(deck 每页一个 slide section)。"""
36
+ return len(re.findall(r"""<section\b[^>]*\bclass\s*=\s*(['"])[^'"]*\bslide\b[^'"]*\1""", html, re.I))
37
+
38
+
39
+ def labeled_page_nums(html: str) -> set:
40
+ """从 data-screen-label="NN ..." 前缀解析已生成页号(乱序生成也能精确 diff)。"""
41
+ return {int(m.group(1)) for m in re.finditer(r'data-screen-label\s*=\s*["\'](\d+)', html, re.I)}
42
+
43
+
44
+ def labeled_page_nums_ordered(html: str) -> list:
45
+ """按 **DOM 顺序**返回 data-screen-label 的数字前缀(保留顺序,用于查页序错乱)。"""
46
+ return [int(m.group(1)) for m in re.finditer(r'data-screen-label\s*=\s*["\'](\d+)', html, re.I)]
47
+
48
+
49
+ def check_order(html: str):
50
+ """返回 (ok, message)。DOM 中各 <section> 的 data-screen-label 数字前缀应**单调递增**——
51
+ 否则导出的 PPTX 播放顺序会与页面编号不符(真机事故:DOM 序 …09,12,13,10,11,15,14…,
52
+ export 按 DOM 位置命名/排序 → 播放顺序错乱)。仅 --check-order 时启用(ppt 专属;webppt 不传)。"""
53
+ nums = labeled_page_nums_ordered(html)
54
+ if len(nums) < 2:
55
+ return (True, f"ORDER_OK: {len(nums)} 个带编号 section,无需查序")
56
+ mism = [(i, nums[i - 1], nums[i]) for i in range(1, len(nums)) if nums[i] < nums[i - 1]]
57
+ seq = ",".join(str(n) for n in nums)
58
+ if not mism:
59
+ return (True, f"ORDER_OK: {len(nums)} 页 DOM 顺序与编号一致 [{seq}]")
60
+ detail = ";".join(f"第 {i + 1} 个 section 编号 {cur} < 前一个 {prev}" for i, prev, cur in mism)
61
+ return (
62
+ False,
63
+ f"ORDER_MISMATCH: DOM 顺序 [{seq}] 非升序 —— {detail}"
64
+ f"(导出按 DOM 位置排序,播放顺序会错;请把各 <section> 按编号从小到大重排)",
65
+ )
66
+
67
+
68
+ def expected_page_nums(design):
69
+ """design.json 的页号列表:优先每页 page 字段,否则按数组序号 1..N。无效返回 None。"""
70
+ pages = design.get("pages") if isinstance(design, dict) else design
71
+ if not isinstance(pages, list) or not pages:
72
+ return None
73
+ nums = []
74
+ for i, p in enumerate(pages, 1):
75
+ if isinstance(p, dict) and isinstance(p.get("page"), int):
76
+ nums.append(p["page"])
77
+ else:
78
+ nums.append(i)
79
+ return nums
80
+
81
+
82
+ def check(deck_path: str, design_path: str):
83
+ """返回 (status, message, exit_code)。status ∈ COMPLETE / MISSING / ERROR。"""
84
+ if not os.path.isfile(design_path):
85
+ return ("ERROR", f"ERROR: design.json 不存在:{design_path}(设计文档步未产出?)", 2)
86
+ try:
87
+ with open(design_path, "r", encoding="utf-8") as f:
88
+ design = json.load(f)
89
+ except (OSError, json.JSONDecodeError) as e:
90
+ return ("ERROR", f"ERROR: design.json 解析失败:{e}", 2)
91
+ expected = expected_page_nums(design)
92
+ if expected is None:
93
+ return ("ERROR", "ERROR: design.json 无有效 pages 数组", 2)
94
+ total = len(expected)
95
+
96
+ html = ""
97
+ if os.path.isfile(deck_path):
98
+ try:
99
+ with open(deck_path, "r", encoding="utf-8") as f:
100
+ html = f.read()
101
+ except OSError as e:
102
+ return ("ERROR", f"ERROR: deck.html 读取失败:{e}", 2)
103
+
104
+ labeled = labeled_page_nums(html)
105
+ sec_count = count_sections(html)
106
+ # 有 data-screen-label → 用页号集合(乱序精确);否则按 section 数当已生成前 N 页。
107
+ done = labeled if labeled else set(range(1, sec_count + 1))
108
+ expected_set = set(expected)
109
+ done_count = len(done & expected_set)
110
+ missing = sorted(expected_set - done)
111
+
112
+ if not missing:
113
+ extra = sec_count - total
114
+ extra_note = f";另有 {extra} 个多余 section(design 仅 {total} 页,请核对)" if extra > 0 else ""
115
+ return ("COMPLETE", f"COMPLETE: {min(done_count, total)}/{total} 页已生成{extra_note}", 0)
116
+ return (
117
+ "MISSING",
118
+ f"MISSING: {','.join(str(n) for n in missing)}(已生成 {done_count}/{total} 页,继续生成缺的页)",
119
+ 1,
120
+ )
121
+
122
+
123
+ def main() -> int:
124
+ parser = argparse.ArgumentParser(
125
+ description="分批 deck 页数完成度闸门(读 design.json 页数 + 数 deck.html section)"
126
+ )
127
+ parser.add_argument("target", help="deck.html 路径,或含 deck.html/design.json 的 workdir 目录")
128
+ parser.add_argument("--design", default=None, help="design.json 路径(缺省按 target 推断)")
129
+ parser.add_argument("--deck", default=None, help="deck.html 路径(target 为目录时可显式指定)")
130
+ parser.add_argument("--check-order", action="store_true",
131
+ help="额外校验 data-screen-label 编号在 DOM 中单调递增(ppt 专属;错乱→ORDER_MISMATCH 非零退出)")
132
+ args = parser.parse_args()
133
+
134
+ if os.path.isdir(args.target):
135
+ deck_path = args.deck or os.path.join(args.target, "deck.html")
136
+ design_path = args.design or os.path.join(args.target, "design.json")
137
+ else:
138
+ deck_path = args.deck or args.target
139
+ design_path = args.design or os.path.join(os.path.dirname(deck_path) or ".", "design.json")
140
+
141
+ _status, message, code = check(deck_path, design_path)
142
+ print(message)
143
+
144
+ if args.check_order and os.path.isfile(deck_path):
145
+ try:
146
+ with open(deck_path, "r", encoding="utf-8") as f:
147
+ order_ok, order_msg = check_order(f.read())
148
+ except OSError as e:
149
+ order_ok, order_msg = True, f"ORDER_SKIP: deck.html 读取失败:{e}"
150
+ print(order_msg)
151
+ if not order_ok and code == 0:
152
+ code = 3 # 页数完整但顺序错乱 → 单独用退出码 3 标记(区分 MISSING=1 / ERROR=2)
153
+
154
+ return code
155
+
156
+
157
+ if __name__ == "__main__":
158
+ sys.exit(main())
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """deck_pages_check.py 回归锚(stdlib unittest)。
4
+
5
+ 运行:python skills/ui-design/scripts/deck_pages_check_test.py
6
+ """
7
+
8
+ import json
9
+ import os
10
+ import shutil
11
+ import sys
12
+ import tempfile
13
+ import unittest
14
+
15
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
16
+ from deck_pages_check import check, check_order # noqa: E402
17
+
18
+
19
+ def deck_html(labels):
20
+ secs = "".join(
21
+ f'<section class="slide cover" data-screen-label="{l}">x</section>' for l in labels
22
+ )
23
+ return f"<html><body>{secs}</body></html>"
24
+
25
+
26
+ def design(n, with_page_field=True):
27
+ if with_page_field:
28
+ return {"pages": [{"page": i, "archetype": "list"} for i in range(1, n + 1)]}
29
+ return {"pages": [{"archetype": "list"} for _ in range(n)]}
30
+
31
+
32
+ class DeckPagesCheckTest(unittest.TestCase):
33
+ def setUp(self):
34
+ self.dir = tempfile.mkdtemp()
35
+
36
+ def tearDown(self):
37
+ shutil.rmtree(self.dir, ignore_errors=True)
38
+
39
+ def _write(self, deck, design_obj):
40
+ dp = os.path.join(self.dir, "deck.html")
41
+ gp = os.path.join(self.dir, "design.json")
42
+ with open(dp, "w", encoding="utf-8") as f:
43
+ f.write(deck)
44
+ with open(gp, "w", encoding="utf-8") as f:
45
+ json.dump(design_obj, f)
46
+ return dp, gp
47
+
48
+ def test_complete(self):
49
+ dp, gp = self._write(deck_html(["01", "02", "03"]), design(3))
50
+ status, msg, code = check(dp, gp)
51
+ self.assertEqual(status, "COMPLETE")
52
+ self.assertEqual(code, 0)
53
+ self.assertIn("COMPLETE", msg)
54
+
55
+ def test_missing_tail(self):
56
+ dp, gp = self._write(deck_html(["01", "02"]), design(5))
57
+ status, msg, code = check(dp, gp)
58
+ self.assertEqual(status, "MISSING")
59
+ self.assertEqual(code, 1)
60
+ self.assertIn("3,4,5", msg)
61
+
62
+ def test_out_of_order_diff(self):
63
+ # 乱序生成(先做 1,5,12)→ 精确 diff 出缺页 2,3,4(5 已生成,12 超范围忽略)。
64
+ dp, gp = self._write(deck_html(["01", "05", "12"]), design(5))
65
+ status, msg, code = check(dp, gp)
66
+ self.assertEqual(status, "MISSING")
67
+ self.assertIn("2,3,4", msg)
68
+
69
+ def test_no_labels_fallback_to_count(self):
70
+ # 无 data-screen-label → 按 section 数当已生成前 N 页。
71
+ deck = '<section class="slide">a</section><section class="slide">b</section>'
72
+ dp, gp = self._write(deck, design(3))
73
+ status, msg, code = check(dp, gp)
74
+ self.assertEqual(status, "MISSING")
75
+ self.assertIn("3", msg)
76
+
77
+ def test_single_quoted_class_counts_slides(self):
78
+ # HTML 合法单引号 class 也必须识别,避免误判 deck 没有页。
79
+ deck = "<section class='slide cover' data-screen-label='01 标题'>a</section>"
80
+ dp, gp = self._write(deck, design(1))
81
+ status, msg, code = check(dp, gp)
82
+ self.assertEqual(status, "COMPLETE")
83
+ self.assertEqual(code, 0)
84
+
85
+ def test_pages_without_page_field(self):
86
+ # pages 无 page 字段 → 按数组序号 1..N。
87
+ dp, gp = self._write(deck_html(["01", "02"]), design(3, with_page_field=False))
88
+ status, msg, code = check(dp, gp)
89
+ self.assertEqual(status, "MISSING")
90
+ self.assertIn("3", msg)
91
+
92
+ def test_design_missing_is_error(self):
93
+ dp = os.path.join(self.dir, "deck.html")
94
+ with open(dp, "w", encoding="utf-8") as f:
95
+ f.write(deck_html(["01"]))
96
+ status, msg, code = check(dp, os.path.join(self.dir, "nope.json"))
97
+ self.assertEqual(status, "ERROR")
98
+ self.assertEqual(code, 2)
99
+
100
+ def test_deck_missing_means_all_missing(self):
101
+ gp = os.path.join(self.dir, "design.json")
102
+ with open(gp, "w", encoding="utf-8") as f:
103
+ json.dump(design(2), f)
104
+ status, msg, code = check(os.path.join(self.dir, "nope.html"), gp)
105
+ self.assertEqual(status, "MISSING")
106
+ self.assertIn("1,2", msg)
107
+
108
+ def test_extra_sections_still_complete(self):
109
+ # deck 多于 design(生成超量)→ 仍 COMPLETE,但提示多余。
110
+ dp, gp = self._write(deck_html(["01", "02", "03", "04"]), design(3))
111
+ status, msg, code = check(dp, gp)
112
+ self.assertEqual(status, "COMPLETE")
113
+ self.assertIn("多余", msg)
114
+
115
+ # ── 页序一致性(--check-order)──
116
+ def test_order_ok_when_ascending(self):
117
+ ok, msg = check_order(deck_html(["01 标题", "02 次页", "03 三页"]))
118
+ self.assertTrue(ok, msg)
119
+ self.assertIn("ORDER_OK", msg)
120
+
121
+ def test_order_mismatch_detected(self):
122
+ # 真机事故序:…09,12,13,10,11,15,14… → 应报 ORDER_MISMATCH。
123
+ ok, msg = check_order(deck_html(["09", "12", "13", "10", "11", "15", "14"]))
124
+ self.assertFalse(ok, msg)
125
+ self.assertIn("ORDER_MISMATCH", msg)
126
+ self.assertIn("10 < 前一个 13", msg)
127
+
128
+ def test_order_single_page_ok(self):
129
+ ok, msg = check_order(deck_html(["01 只有一页"]))
130
+ self.assertTrue(ok, msg)
131
+
132
+
133
+ if __name__ == "__main__":
134
+ unittest.main(verbosity=2)