minimal-agent 0.9.0 → 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.
- package/README.md +11 -8
- package/package.json +34 -1
- package/plugins/cron-runner/.claude-plugin/plugin.json +5 -0
- package/plugins/cron-runner/commands/cron.md +26 -0
- package/plugins/cron-runner/commands/crons.md +7 -0
- package/plugins/cron-runner/plugin.js +34 -0
- package/plugins/cron-runner/src/commands.js +348 -0
- package/plugins/cron-runner/src/cronTime.js +148 -0
- package/plugins/cron-runner/src/lock.js +68 -0
- package/plugins/cron-runner/src/runs.js +89 -0
- package/plugins/cron-runner/src/scheduleEngine.js +72 -0
- package/plugins/cron-runner/src/scheduler.js +355 -0
- package/plugins/cron-runner/src/schema.js +140 -0
- package/plugins/cron-runner/src/service.js +167 -0
- package/plugins/cron-runner/src/store.js +298 -0
- package/plugins/cron-runner/src/types.js +1 -0
- package/plugins/workflow-runner/commands/workflow.md +4 -4
- package/plugins/workflow-runner/commands/workflows.md +1 -1
- package/plugins/workflow-runner/plugin.js +2 -1
- package/plugins/workflow-runner/src/agentCommon.js +172 -9
- package/plugins/workflow-runner/src/dslManifest.js +72 -0
- package/plugins/workflow-runner/src/expressions.js +150 -13
- package/plugins/workflow-runner/src/index.js +39 -8
- package/plugins/workflow-runner/src/loader.js +216 -64
- package/plugins/workflow-runner/src/multimodal.js +37 -0
- package/plugins/workflow-runner/src/recovery.js +26 -24
- package/plugins/workflow-runner/src/runner.js +693 -287
- package/plugins/workflow-runner/src/stepExecutors/agent.js +126 -37
- package/plugins/workflow-runner/src/stepExecutors/assert.js +3 -2
- package/plugins/workflow-runner/src/stepExecutors/llm.js +38 -30
- package/plugins/workflow-runner/src/stepExecutors/skill.js +27 -38
- package/plugins/workflow-runner/src/stepExecutors/tool.js +56 -3
- package/plugins/workflow-runner/src/stepExecutors/verify.js +19 -10
- package/plugins/workflow-runner/src/taskIdentity.js +185 -30
- package/plugins/workflow-runner/src/types.js +18 -7
- package/plugins/workflow-runner/src/workflowState.js +355 -55
- package/skills/ai-image/SKILL.md +89 -0
- package/skills/ai-image/scripts/generate.mjs +497 -0
- package/skills/ai-image/scripts/generate_from_plan.mjs +469 -0
- package/skills/ai-image/scripts/generate_from_plan_test.mjs +223 -0
- package/skills/ai-image/scripts/generate_test.mjs +74 -0
- package/skills/browser-automation/SKILL.md +47 -0
- package/skills/docx/SKILL.md +25 -3
- package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
- package/skills/docx/scripts/opc_check.py +253 -0
- package/skills/image-gen-openrouter/SKILL.md +10 -2
- package/skills/image-stats/SKILL.md +65 -0
- package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/image_stats.py +368 -0
- package/skills/image-stats/scripts/image_stats_test.py +181 -0
- package/skills/pptx/SKILL.md +123 -95
- package/skills/pptx/design.md +82 -0
- package/skills/pptx/examples/README.md +29 -0
- package/skills/pptx/examples/hybrid_example.mjs +107 -0
- package/skills/pptx/examples/hybrid_example.pptx +0 -0
- package/skills/pptx/pptxgenjs.md +41 -0
- package/skills/pptx/scripts/deck_helpers.mjs +224 -0
- package/skills/pptx/scripts/layout_lint.py +293 -0
- package/skills/pptx/scripts/layout_lint_test.py +160 -0
- package/skills/pptx/scripts/opc_check.py +339 -0
- package/skills/pptx/scripts/svg_fallback.mjs +145 -0
- package/skills/pptx/svg.md +67 -0
- package/skills/tts-zh/SKILL.md +19 -2
- package/skills/ui-design/SKILL.md +158 -0
- package/skills/ui-design/claude_design.md +309 -0
- package/skills/ui-design/evals/evals.json +254 -0
- package/skills/ui-design/references/aesthetic-direction.md +83 -0
- package/skills/ui-design/references/claude-design-protocol.md +36 -0
- package/skills/ui-design/references/design-context.md +53 -0
- package/skills/ui-design/references/design-execution-playbook.md +82 -0
- package/skills/ui-design/references/export-pptx.md +124 -0
- package/skills/ui-design/references/layout-composition.md +654 -0
- package/skills/ui-design/references/preview-feedback.md +37 -0
- package/skills/ui-design/references/source-image-layout.md +189 -0
- package/skills/ui-design/references/starter-components.md +78 -0
- package/skills/ui-design/references/vi-aegis-vector.md +144 -0
- package/skills/ui-design/references/vi-amber-prism.md +133 -0
- package/skills/ui-design/references/vi-aqua-glass.md +200 -0
- package/skills/ui-design/references/vi-comfort-vision.md +147 -0
- package/skills/ui-design/references/vi-ember-prism.md +140 -0
- package/skills/ui-design/references/vi-nebula-console.md +151 -0
- package/skills/ui-design/references/vi-obsidian-optics.md +139 -0
- package/skills/ui-design/references/vi-obsidian-xui.md +143 -0
- package/skills/ui-design/references/vi-precision-horizon-dark.md +117 -0
- package/skills/ui-design/references/vi-precision-horizon.md +215 -0
- package/skills/ui-design/references/vi-solar-relay.md +130 -0
- package/skills/ui-design/references/vi-template-workflow.md +48 -0
- package/skills/ui-design/references/vi-verdant-grid.md +141 -0
- package/skills/ui-design/references/vi-violet-meridian.md +172 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/assemble_material.py +217 -0
- package/skills/ui-design/scripts/assemble_material_test.py +149 -0
- package/skills/ui-design/scripts/browser_check_ui_artifact.mjs +221 -0
- package/skills/ui-design/scripts/chart_sanity_check.py +261 -0
- package/skills/ui-design/scripts/chart_sanity_check_test.py +165 -0
- package/skills/ui-design/scripts/check_language_policy.py +351 -0
- package/skills/ui-design/scripts/check_ui_artifact.py +435 -0
- package/skills/ui-design/scripts/check_ui_artifact_pptx_test.py +251 -0
- package/skills/ui-design/scripts/deck_pages_check.py +158 -0
- package/skills/ui-design/scripts/deck_pages_check_test.py +134 -0
- package/skills/ui-design/scripts/deck_visual_style_check.py +767 -0
- package/skills/ui-design/scripts/deck_visual_style_check_test.py +713 -0
- package/skills/ui-design/scripts/design_budget_check.py +271 -0
- package/skills/ui-design/scripts/design_budget_check_test.py +183 -0
- package/skills/ui-design/scripts/design_repair_hints.py +162 -0
- package/skills/ui-design/scripts/design_repair_hints_test.py +54 -0
- package/skills/ui-design/scripts/design_style_check.py +397 -0
- package/skills/ui-design/scripts/design_style_check_test.py +233 -0
- package/skills/ui-design/scripts/draft_coverage_check.py +184 -0
- package/skills/ui-design/scripts/draft_coverage_check_test.py +131 -0
- package/skills/ui-design/scripts/export_pptx_from_html.mjs +2367 -0
- package/skills/ui-design/scripts/extract_source_assets.py +607 -0
- package/skills/ui-design/scripts/extract_source_assets_test.py +256 -0
- package/skills/ui-design/scripts/generated_image_review_collect.py +206 -0
- package/skills/ui-design/scripts/generated_image_review_collect_test.py +91 -0
- package/skills/ui-design/scripts/image_plan_lint.py +571 -0
- package/skills/ui-design/scripts/image_plan_lint_test.py +515 -0
- package/skills/ui-design/scripts/image_prompt_rewrite.py +713 -0
- package/skills/ui-design/scripts/image_prompt_rewrite_test.py +966 -0
- package/skills/ui-design/scripts/layout_balance.py +881 -0
- package/skills/ui-design/scripts/layout_balance_test.py +927 -0
- package/skills/ui-design/scripts/normalize_design_json.py +272 -0
- package/skills/ui-design/scripts/normalize_design_json_test.py +119 -0
- package/skills/ui-design/scripts/plan_source_layout.py +1450 -0
- package/skills/ui-design/scripts/plan_source_layout_test.py +1136 -0
- package/skills/ui-design/scripts/resolve_source_input.py +270 -0
- package/skills/ui-design/scripts/resolve_source_input_test.py +98 -0
- package/skills/ui-design/scripts/scaffold_ui_artifact.py +377 -0
- package/skills/ui-design/scripts/source_usage_check.py +581 -0
- package/skills/ui-design/scripts/source_usage_check_test.py +427 -0
- package/skills/ui-design/scripts/text_readability_pixel.py +340 -0
- package/skills/ui-design/scripts/text_readability_pixel_test.py +219 -0
- package/skills/ui-design/scripts/visual_quality_gate.py +301 -0
- package/skills/ui-design/scripts/visual_quality_gate_test.py +233 -0
- package/skills/ui-design/tests/e2e/prompts/deck.md +19 -0
- package/skills/ui-design/tests/e2e/prompts/webpage.md +17 -0
- package/skills/ui-design/tests/e2e/render_check.mjs +101 -0
- package/skills/ui-design/tests/e2e/rubric.json +54 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/language-check.txt +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/static-check.txt +15 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/outputs/index.html +837 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/review.md +21 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/outputs/index.html +656 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/render_check.mjs +67 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/review.md +36 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/language-check.txt +8 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/static-check.txt +16 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/outputs/index.html +739 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/prompt.md +11 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/review.md +22 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/checks/browser-check.json +52 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/outputs/index.html +641 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/outputs/index.html +467 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/language-check.txt +4 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/execution_notes.md +10 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/review.md +13 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/browser-check.json +24 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/execution_notes.md +21 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/outputs/deck.html +451 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-01.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-02.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/review.md +79 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/browser-check.json +26 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/execution_notes.md +20 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/outputs/index.html +534 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/browser-check.json +64 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/language-check.txt +7 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-console.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-homepage.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/console.html +600 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/homepage.html +556 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/prompt.md +29 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/review.md +57 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/browser-check.json +33 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/outputs/index.html +682 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-01.html +466 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-02.html +433 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/language-check.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/execution_notes.md +24 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/outputs/index.html +723 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-dark.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-light.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/language-check.txt +11 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-dark.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-light.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/execution_notes.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/dark.html +392 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/light.html +476 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/prompt.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/review.md +41 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/language-check.txt +5 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/outputs/index.html +765 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/outputs/index.html +508 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/outputs/index.html +788 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/review.md +60 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/mobile.png +0 -0
- package/skills/video-compose/SKILL.md +8 -1
- package/skills/web-crawler/SKILL.md +70 -0
- package/skills/web-crawler/scripts/crawl.mjs +538 -0
- package/skills/web-crawler/scripts/crawl.test.mjs +204 -0
- package/skills/xlsx/SKILL.md +12 -0
- package/skills/xlsx/scripts/opc_check.py +253 -0
- package/src/advisorState.js +22 -0
- package/src/askBridge.js +87 -3
- package/src/bootstrap/workingDir.js +12 -1
- package/src/cli/args.js +17 -1
- package/src/cli/configMenu.js +236 -0
- package/src/cli/configWizard.js +7 -5
- package/src/cli/print.js +37 -4
- package/src/cli/streamJson.js +77 -24
- package/src/cli/wizards/advisorWizard.js +147 -0
- package/src/cli/wizards/fieldForm.js +149 -0
- package/src/cli/wizards/imageWizard.js +60 -0
- package/src/cli/wizards/openRouterWizard.js +23 -0
- package/src/cli/wizards/providerPresets.js +95 -0
- package/src/cli/wizards/providerWizard.js +219 -0
- package/src/cli/wizards/searchWizard.js +23 -0
- package/src/cli/wizards/ttsWizard.js +34 -0
- package/src/config/configFile.js +441 -83
- package/src/config/configService.js +446 -0
- package/src/config.js +24 -64
- package/src/context/agentHome.js +9 -0
- package/src/context/archive.js +3 -2
- package/src/context/compact.js +8 -5
- package/src/context/contextLock.js +81 -0
- package/src/context/persistContext.js +30 -11
- package/src/context/reactiveCompact.js +4 -2
- package/src/context/recentDirs.js +21 -61
- package/src/context/sessionPath.js +97 -23
- package/src/context/sessionRegistry.js +303 -24
- package/src/context/tokenCounter.js +18 -0
- package/src/context/workspaceIndex.js +731 -0
- package/src/infra/verification.js +3 -2
- package/src/llm/client.js +293 -206
- package/src/llm/providers/anthropicFormat.js +241 -0
- package/src/llm/providers/openaiFormat.js +190 -0
- package/src/loop.js +211 -27
- package/src/main.js +61 -11
- package/src/messageQueue.js +97 -0
- package/src/multimodal.js +203 -0
- package/src/plugin-sdk.js +15 -0
- package/src/plugins/commandRouter.js +3 -0
- package/src/plugins/hookEngine.js +5 -1
- package/src/plugins/pluginLifecycle.js +28 -0
- package/src/plugins/pluginRunner.js +40 -0
- package/src/plugins/transcript.js +4 -3
- package/src/prompts/pluginList.js +2 -2
- package/src/prompts/projectInstructions.js +3 -3
- package/src/prompts/promptAssembly.js +133 -109
- package/src/prompts/skillList.js +12 -22
- package/src/session/runAgentTurn.js +70 -0
- package/src/session/runTurn.js +41 -6
- package/src/toolGate.js +17 -0
- package/src/tools/advisor/advisor.js +379 -0
- package/src/tools/agent/agent.js +555 -0
- package/src/tools/agent/agentTypes.js +59 -0
- package/src/tools/agent/coordinator.js +93 -0
- package/src/tools/agent/worktree.js +270 -0
- package/src/tools/ask/ask.js +7 -2
- package/src/tools/bash/bash.js +112 -18
- package/src/tools/download/download.js +144 -0
- package/src/tools/edit/edit.js +1 -0
- package/src/tools/edit/multi-edit.js +1 -0
- package/src/tools/genimage/genimage.js +242 -0
- package/src/tools/genspeech/genspeech.js +67 -0
- package/src/tools/glob/glob.js +1 -0
- package/src/tools/grep/grep.js +3 -0
- package/src/tools/grep/rgPath.js +2 -0
- package/src/tools/index.js +25 -2
- package/src/tools/read/read.js +1 -0
- package/src/tools/shared/killTree.js +52 -0
- package/src/tools/toolProgressBridge.js +48 -0
- package/src/tools/webbrowser/agentBrowserPath.js +258 -0
- package/src/tools/webbrowser/browser.js +59 -42
- package/src/tools/webbrowser/browserControl.js +118 -0
- package/src/tools/webbrowser/browserDaemon.js +97 -0
- package/src/tools/webbrowser/browserService.js +27 -0
- package/src/tools/webbrowser/browserStream.js +119 -0
- package/src/tools/webbrowser/webbrowser.js +699 -130
- package/src/tools/webfetch/webfetch.js +1 -0
- package/src/tools/websearch/websearch.js +134 -51
- package/src/tools/write/write.js +1 -0
- package/src/ui/App.js +249 -22
- package/src/ui/AskQuestion.js +19 -17
- package/src/ui/InputBox.js +34 -9
- package/src/ui/LiveArea.js +112 -19
- package/src/ui/MessageList.js +100 -14
- package/src/ui/ModelPicker.js +56 -0
- package/src/ui/QueuedMessagesBanner.js +14 -0
- package/src/ui/Root.js +18 -10
- package/src/ui/SessionPicker.js +102 -0
- package/src/ui/StatusLine.js +13 -4
- package/src/ui/WorkspacePicker.js +55 -0
- package/src/ui/figures.js +44 -0
- package/src/ui/hooks/askSlot.js +82 -0
- package/src/ui/hooks/useChat.js +345 -64
- package/src/ui/hooks/usePasteHandler.js +11 -1
- package/src/ui/hooks/useTextBuffer.js +1 -3
- package/src/ui/liveViewport.js +5 -1
- package/src/ui/markdown.js +206 -0
- package/src/ui/textBuffer.js +0 -7
- package/src/ui/theme.js +32 -0
- package/src/utils/debugLog.js +0 -4
- package/src/utils/resourcePaths.js +2 -2
- package/src/utils/stripThink.js +50 -0
- package/src/web/browserBridge.js +447 -0
- package/src/web/protocol.js +19 -0
- package/workflows/adaptive-research.yaml +9 -2
- package/workflows/book-review-short.yaml +31 -7
- package/workflows/e2e-write-greet.yaml +3 -0
- package/workflows/illustrate.yaml +227 -0
- package/workflows/plan.yaml +437 -207
- package/workflows/ppt.yaml +1659 -0
- package/workflows/ralph-loop.yaml +142 -112
- package/workflows/schema.json +81 -23
- package/workflows/webppt.yaml +496 -0
- package/workflows/word.yaml +710 -0
- package/workflows/youtube-shorts.yaml +38 -10
- package/MINIMAL-TRACE.md +0 -77
- package/plugins/workflow-runner/src/voteHelpers.js +0 -110
- package/skills/config/SKILL.md +0 -123
- package/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/frontend-design/SKILL.md +0 -42
- package/skills/pptx/scripts/office/__pycache__/soffice.cpython-314.pyc +0 -0
- package/src/ui/ProgressPanel.js +0 -54
- package/src/ui/StreamingBlock.js +0 -11
- package/src/ui/ToolStatus.js +0 -11
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Static checks for ui-design HTML artifacts."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
PINNED_SCRIPTS = {
|
|
15
|
+
"react": (
|
|
16
|
+
"https://unpkg.com/react@18.3.1/umd/react.development.js",
|
|
17
|
+
"sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L",
|
|
18
|
+
),
|
|
19
|
+
"react-dom": (
|
|
20
|
+
"https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js",
|
|
21
|
+
"sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm",
|
|
22
|
+
),
|
|
23
|
+
"babel": (
|
|
24
|
+
"https://unpkg.com/@babel/standalone@7.29.0/babel.min.js",
|
|
25
|
+
"sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y",
|
|
26
|
+
),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class Finding:
|
|
32
|
+
severity: str
|
|
33
|
+
message: str
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def has_react_or_babel(content: str) -> bool:
|
|
37
|
+
# 只认**真 React/Babel 件**的信号:text/babel 脚本、react/babel 的 CDN <script src>、或 React API 使用。
|
|
38
|
+
# **不**靠正文里出现 "React"/"babel" 字样——讲技术栈的 deck 常把 "React + Next.js" 当**内容**写,
|
|
39
|
+
# 过去子串匹配把它误判成 React 件、逼着补 pinned react 脚本(对静态 deck 是假的阻断 ERROR)。
|
|
40
|
+
lowered = content.lower()
|
|
41
|
+
if 'type="text/babel"' in lowered or "type='text/babel'" in lowered:
|
|
42
|
+
return True
|
|
43
|
+
if re.search(r"<script\b[^>]+src=[\"'][^\"']*(?:react|babel)[^\"']*[\"']", lowered):
|
|
44
|
+
return True
|
|
45
|
+
if re.search(r"\b(?:reactdom|react\.createelement|createroot)\b", lowered):
|
|
46
|
+
return True
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def check_pinned_scripts(content: str, findings: list[Finding]) -> None:
|
|
51
|
+
if not has_react_or_babel(content):
|
|
52
|
+
return
|
|
53
|
+
for name, (src, integrity) in PINNED_SCRIPTS.items():
|
|
54
|
+
if src not in content:
|
|
55
|
+
findings.append(Finding("error", f"React/Babel artifact is missing pinned {name} script: {src}"))
|
|
56
|
+
if integrity not in content:
|
|
57
|
+
findings.append(Finding("error", f"React/Babel artifact is missing {name} integrity hash."))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def check_file_size(content: str, findings: list[Finding]) -> None:
|
|
61
|
+
line_count = content.count("\n") + 1
|
|
62
|
+
if line_count > 1000:
|
|
63
|
+
findings.append(
|
|
64
|
+
Finding(
|
|
65
|
+
"warning",
|
|
66
|
+
f"HTML artifact is {line_count} lines. Large prototypes should split CSS/JS/JSX or components.",
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def check_react_babel_structure(content: str, findings: list[Finding]) -> None:
|
|
72
|
+
if not has_react_or_babel(content):
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
if re.search(r"<script[^>]+type=[\"']module[\"']", content, re.I):
|
|
76
|
+
findings.append(
|
|
77
|
+
Finding(
|
|
78
|
+
"warning",
|
|
79
|
+
"React/Babel inline JSX artifacts should not mix in type=\"module\" scripts for helpers.",
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if re.search(r"\bconst\s+styles\s*=", content):
|
|
84
|
+
findings.append(
|
|
85
|
+
Finding(
|
|
86
|
+
"warning",
|
|
87
|
+
"Avoid global const styles = {}; it can collide with starter components or other scripts.",
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
babel_count = len(re.findall(r"<script[^>]+type=[\"']text/babel[\"']", content, re.I))
|
|
92
|
+
if babel_count > 1 and "Object.assign(window" not in content:
|
|
93
|
+
findings.append(
|
|
94
|
+
Finding(
|
|
95
|
+
"warning",
|
|
96
|
+
"Multiple text/babel scripts should expose shared components with Object.assign(window, ...).",
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def check_tweaks(content: str, findings: list[Finding]) -> None:
|
|
102
|
+
starts = list(re.finditer(r"/\*EDITMODE-BEGIN\*/", content))
|
|
103
|
+
ends = list(re.finditer(r"/\*EDITMODE-END\*/", content))
|
|
104
|
+
if not starts and not ends:
|
|
105
|
+
findings.append(Finding("warning", "No Tweaks JSON block found. Add one when variants or live design controls are useful."))
|
|
106
|
+
return
|
|
107
|
+
if len(starts) != 1 or len(ends) != 1:
|
|
108
|
+
findings.append(Finding("error", "Expected exactly one /*EDITMODE-BEGIN*/ ... /*EDITMODE-END*/ JSON block."))
|
|
109
|
+
return
|
|
110
|
+
if starts[0].end() > ends[0].start():
|
|
111
|
+
findings.append(Finding("error", "Tweaks JSON markers are in the wrong order."))
|
|
112
|
+
return
|
|
113
|
+
raw_json = content[starts[0].end() : ends[0].start()].strip()
|
|
114
|
+
try:
|
|
115
|
+
json.loads(raw_json)
|
|
116
|
+
except json.JSONDecodeError as exc:
|
|
117
|
+
findings.append(Finding("error", f"Tweaks block is not valid JSON: {exc}"))
|
|
118
|
+
|
|
119
|
+
if "__activate_edit_mode" not in content or "__deactivate_edit_mode" not in content:
|
|
120
|
+
findings.append(Finding("warning", "Tweaks block exists, but edit-mode activate/deactivate listener was not found."))
|
|
121
|
+
if "__edit_mode_available" not in content:
|
|
122
|
+
findings.append(Finding("warning", "Tweaks block exists, but __edit_mode_available announcement was not found."))
|
|
123
|
+
if "__edit_mode_set_keys" not in content:
|
|
124
|
+
findings.append(Finding("warning", "Tweaks block exists, but __edit_mode_set_keys persistence was not found."))
|
|
125
|
+
|
|
126
|
+
available_idx = content.find("__edit_mode_available")
|
|
127
|
+
activate_idx = content.find("__activate_edit_mode")
|
|
128
|
+
if available_idx != -1 and activate_idx != -1 and available_idx < activate_idx:
|
|
129
|
+
findings.append(
|
|
130
|
+
Finding(
|
|
131
|
+
"warning",
|
|
132
|
+
"Register the edit-mode message listener before announcing __edit_mode_available.",
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if "__edit_mode_set_keys" in content and not re.search(r"(\bedits\s*:|[\"']edits[\"'])", content):
|
|
137
|
+
findings.append(
|
|
138
|
+
Finding(
|
|
139
|
+
"warning",
|
|
140
|
+
"Tweaks persistence should prefer an edits payload; legacy keys payloads are only compatibility.",
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def check_deck_and_fixed_size(content: str, findings: list[Finding], for_pptx_export: bool = False) -> None:
|
|
146
|
+
looks_fixed_size = bool(re.search(r"\b(1920|1080|16:9|slide|deck|presentation|stage)\b", content, re.I))
|
|
147
|
+
labels = re.findall(r'data-screen-label=["\']([^"\']+)["\']', content)
|
|
148
|
+
if not labels:
|
|
149
|
+
findings.append(Finding("warning", "No data-screen-label found. Label the main screen so preview feedback and screenshots can identify it."))
|
|
150
|
+
if not looks_fixed_size:
|
|
151
|
+
return
|
|
152
|
+
# 「持久化当前页 / 视口缩放」是浏览器内交互观看的诉求。导出 PPTX 时 deck 是**静态导出目标**
|
|
153
|
+
# (导出脚本自己控制每页 hidden、强制 1920×1080),这些 web-app 件不需要、也不该提示——
|
|
154
|
+
# 否则诱导弱模型去补 localStorage/scale 而非修构图。
|
|
155
|
+
if not for_pptx_export:
|
|
156
|
+
if not re.search(r"localStorage|slideIndexChanged|activeSlide|currentSlide", content):
|
|
157
|
+
findings.append(Finding("warning", "Slide/deck-like artifact should persist current slide or playback position."))
|
|
158
|
+
if not re.search(r"transform\s*:\s*scale|style\.transform|scale\(", content):
|
|
159
|
+
findings.append(Finding("warning", "Fixed-size artifact should include viewport scaling via transform: scale()."))
|
|
160
|
+
if "transform-origin" not in content:
|
|
161
|
+
findings.append(Finding("warning", "Fixed-size artifact should set transform-origin for stable viewport scaling."))
|
|
162
|
+
|
|
163
|
+
if any(label.startswith("00 ") for label in labels):
|
|
164
|
+
findings.append(Finding("warning", "Slide labels should be 1-indexed; verify labels do not start from 00."))
|
|
165
|
+
if labels and not any(re.search(r"[\u4e00-\u9fff]", label) for label in labels):
|
|
166
|
+
findings.append(Finding("warning", "Slide/screen labels should include Chinese titles, not only numeric or English labels."))
|
|
167
|
+
|
|
168
|
+
if not for_pptx_export:
|
|
169
|
+
stage_match = re.search(
|
|
170
|
+
r"<main\b[^>]*(?:id|class)=[\"'][^\"']*scaled-stage[^\"']*[\"'][^>]*>.*?</main>",
|
|
171
|
+
content,
|
|
172
|
+
re.I | re.S,
|
|
173
|
+
)
|
|
174
|
+
if stage_match and "stage-controls" in stage_match.group(0):
|
|
175
|
+
findings.append(Finding("warning", "Stage controls appear to be inside the scaled stage; keep controls outside scaled content."))
|
|
176
|
+
|
|
177
|
+
looks_time_based = bool(
|
|
178
|
+
re.search(r"\b(animation|video|timeline|play-toggle|isPlaying|currentTime|scrubber|播放)\b", content, re.I)
|
|
179
|
+
)
|
|
180
|
+
if looks_time_based and not re.search(r"localStorage|currentTime|isPlaying|playback|playing", content):
|
|
181
|
+
findings.append(Finding("warning", "Animation/video-like artifacts should persist playback or time state."))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def check_speaker_notes(content: str, findings: list[Finding]) -> None:
|
|
185
|
+
if re.search(r"id=[\"']speaker-notes[\"']", content, re.I) and "slideIndexChanged" not in content:
|
|
186
|
+
findings.append(Finding("error", "speaker-notes are present but slideIndexChanged synchronization was not found."))
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def check_placeholders(content: str, findings: list[Finding]) -> None:
|
|
190
|
+
placeholder_patterns = [
|
|
191
|
+
r"lorem ipsum",
|
|
192
|
+
r"\bTODO\b",
|
|
193
|
+
r"\bplaceholder\b",
|
|
194
|
+
r"replace this",
|
|
195
|
+
r"dummy (text|content|data)",
|
|
196
|
+
]
|
|
197
|
+
for pattern in placeholder_patterns:
|
|
198
|
+
if re.search(pattern, content, re.I):
|
|
199
|
+
findings.append(Finding("warning", f"Possible unfinished placeholder content matched: {pattern}"))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def check_basic_html(content: str, findings: list[Finding]) -> None:
|
|
203
|
+
lowered = content.lower()
|
|
204
|
+
for tag in ("<!doctype html", "<html", "<head", "<body"):
|
|
205
|
+
if tag not in lowered:
|
|
206
|
+
findings.append(Finding("error", f"Missing basic HTML structure: {tag}"))
|
|
207
|
+
if len(re.findall(r"<head\b", content, re.I)) > 1:
|
|
208
|
+
findings.append(Finding("error", "Multiple <head> tags found. The HTML document is likely concatenated or malformed."))
|
|
209
|
+
if len(re.findall(r"<body\b", content, re.I)) > 1:
|
|
210
|
+
findings.append(Finding("error", "Multiple <body> tags found. The HTML document is likely concatenated or malformed."))
|
|
211
|
+
if "<title" not in lowered:
|
|
212
|
+
findings.append(Finding("warning", "Missing <title>."))
|
|
213
|
+
if "name=\"viewport\"" not in lowered and "name='viewport'" not in lowered:
|
|
214
|
+
findings.append(Finding("warning", "Missing viewport meta tag."))
|
|
215
|
+
if not re.search(r"<html[^>]+lang=[\"']zh-CN[\"']", content, re.I):
|
|
216
|
+
findings.append(Finding("warning", "Chinese ui-design artifacts should set <html lang=\"zh-CN\">."))
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def mask_blocks_keep_newlines(content: str, pattern: str) -> str:
|
|
220
|
+
def repl(match: re.Match[str]) -> str:
|
|
221
|
+
text = match.group(0)
|
|
222
|
+
return "".join("\n" if ch == "\n" else " " for ch in text)
|
|
223
|
+
|
|
224
|
+
return re.sub(pattern, repl, content, flags=re.I | re.S)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_malformed_visible_css(content: str, findings: list[Finding]) -> None:
|
|
228
|
+
masked = content
|
|
229
|
+
for pattern in (
|
|
230
|
+
r"<style\b[^>]*>.*?</style>",
|
|
231
|
+
r"<script\b[^>]*>.*?</script>",
|
|
232
|
+
r"<!--.*?-->",
|
|
233
|
+
):
|
|
234
|
+
masked = mask_blocks_keep_newlines(masked, pattern)
|
|
235
|
+
|
|
236
|
+
if re.search(r"^\s*/\*\s*=.{10,}", masked, re.M):
|
|
237
|
+
findings.append(
|
|
238
|
+
Finding(
|
|
239
|
+
"error",
|
|
240
|
+
"CSS comment block appears outside <style>. This will render as visible text and break PPTX export layers.",
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
if re.search(r"^\s*(?:\.[A-Za-z_-][\w-]*|#[A-Za-z_-][\w-]*|[A-Za-z_-][\w-]*(?:\s+[.#A-Za-z_-]))[^{\n]{0,120}\{\s*$", masked, re.M):
|
|
245
|
+
findings.append(
|
|
246
|
+
Finding(
|
|
247
|
+
"error",
|
|
248
|
+
"CSS selector appears outside <style>. Wrap late CSS blocks in <style> before exporting.",
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def check_visual_risks(content: str, findings: list[Finding]) -> None:
|
|
254
|
+
if re.search(r"letter-spacing\s*:\s*-\d", content):
|
|
255
|
+
findings.append(Finding("warning", "Avoid negative letter-spacing; it is especially risky for Chinese typography."))
|
|
256
|
+
|
|
257
|
+
if re.search(r"font-size\s*:\s*clamp\([^;]*,\s*(?:8[4-9]|9\d|1\d\d)px\)", content):
|
|
258
|
+
findings.append(Finding("warning", "Very large clamp() title size found. Chinese H1 should usually stay at or below 72-80px."))
|
|
259
|
+
|
|
260
|
+
for match in re.finditer(r"font-size\s*:\s*(\d+(?:\.\d+)?)px", content):
|
|
261
|
+
size = float(match.group(1))
|
|
262
|
+
before = content[max(0, match.start() - 160):match.start()].lower()
|
|
263
|
+
if size > 84 and ("h1" in before or "hero" in before or "title" in before):
|
|
264
|
+
findings.append(Finding("warning", f"Very large title-like font-size found: {size:g}px. Check Chinese line breaks in screenshots."))
|
|
265
|
+
break
|
|
266
|
+
|
|
267
|
+
low_alpha_glass = re.findall(r"rgba\(\s*255\s*,\s*255\s*,\s*255\s*,\s*0\.(?:[0-5]\d?|59)\s*\)", content)
|
|
268
|
+
if low_alpha_glass and ("backdrop-filter" in content or "glass" in content.lower()):
|
|
269
|
+
findings.append(Finding("warning", "Low-opacity white glass surface found. Ensure text remains readable over gradients."))
|
|
270
|
+
|
|
271
|
+
if "backdrop-filter" in content and not re.search(r"linear-gradient|radial-gradient", content):
|
|
272
|
+
findings.append(Finding("warning", "Glass style uses backdrop-filter without gradients. Consider adding gradient light, edge highlights, and layer contrast."))
|
|
273
|
+
|
|
274
|
+
if re.search(r"backdrop-filter", content) and len(re.findall(r"backdrop-filter", content)) >= 4:
|
|
275
|
+
findings.append(Finding("warning", "Many backdrop-filter surfaces found. Ensure glass is not replacing structure, gradients, and readable hierarchy."))
|
|
276
|
+
|
|
277
|
+
if re.search(r"(conic-gradient|linear-gradient|radial-gradient)", content) and re.search(
|
|
278
|
+
r"rgba\(\s*255\s*,\s*255\s*,\s*255\s*,\s*0\.[0-6]", content
|
|
279
|
+
):
|
|
280
|
+
findings.append(Finding("warning", "Gradient-heavy design with low-opacity white surfaces found. Confirm text contrast in browser screenshots."))
|
|
281
|
+
|
|
282
|
+
if re.search(r"font-size\s*:\s*(?:[0-9](?:\.\d+)?px|1[0-1](?:\.\d+)?px|0\.[0-7]rem)", content):
|
|
283
|
+
findings.append(Finding("warning", "Very small text size found. Chinese UI text below 12px is usually hard to read."))
|
|
284
|
+
|
|
285
|
+
button_blocks = re.findall(r"(?:button|\.btn|\.cta)[^{]{0,80}\{[^}]+\}", content, re.I | re.S)
|
|
286
|
+
if button_blocks:
|
|
287
|
+
has_touch_size = any(re.search(r"(min-height|height)\s*:\s*(4[4-9]|[5-9]\d)px", block) for block in button_blocks)
|
|
288
|
+
if not has_touch_size:
|
|
289
|
+
findings.append(Finding("warning", "Button-like styles found without an obvious 44px min-height. Check mobile hit targets."))
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
OVERUSED_FONTS = ("inter", "roboto", "fraunces", "arial")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def check_overused_font(content: str, findings: list[Finding]) -> None:
|
|
296
|
+
# 铁律「避免过度常见字体栈」(SKILL.md:119 / claude_design.md:255)此前只在 prose 层、无机械背书。
|
|
297
|
+
# 这里只判 `font-family` 声明的**首个**字体族:CJK 栈把 Arial/Helvetica 列作**末位** Latin 兜底
|
|
298
|
+
# 是合法实践(scaffold 默认栈即 PingFang…→Arial→sans-serif),故**不**因末位兜底误报——只有
|
|
299
|
+
# Inter/Roboto/Fraunces 当**主字体**才是模板味。WARNING 级、不改 exit code(不硬拦弱模型)。
|
|
300
|
+
for match in re.finditer(r"font-family\s*:\s*([^;}]+)", content, re.I):
|
|
301
|
+
first = match.group(1).split(",")[0].strip().strip("'\"").lower()
|
|
302
|
+
if first in OVERUSED_FONTS:
|
|
303
|
+
findings.append(
|
|
304
|
+
Finding(
|
|
305
|
+
"warning",
|
|
306
|
+
f"Overused font family as the primary typeface: '{first}'. Avoid Inter/Roboto/Fraunces as the leading font; commit to a brand or display face that carries the visual direction.",
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
break
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def check_left_border_accent(content: str, findings: list[Finding]) -> None:
|
|
313
|
+
# 经典「左边框强调 + 圆角卡」是 claude_design.md:253 点名禁的 AI 味。确定性判定:**同一规则块内**
|
|
314
|
+
# `border-left: <2–8px> solid <色>` 与 `border-radius` 共现 → WARNING(普通无圆角的左边框、或跨块
|
|
315
|
+
# 各自出现都不报,避免误伤)。WARNING 级、不改 exit code。
|
|
316
|
+
for block in re.finditer(r"\{([^{}]*)\}", content):
|
|
317
|
+
body = block.group(1)
|
|
318
|
+
if not re.search(r"border-radius\s*:", body, re.I):
|
|
319
|
+
continue
|
|
320
|
+
if re.search(r"border-left\s*:\s*[^;]*\b[2-8]px\s+solid\b", body, re.I):
|
|
321
|
+
findings.append(
|
|
322
|
+
Finding(
|
|
323
|
+
"warning",
|
|
324
|
+
"Left-border accent card detected (border-left <2-8px> solid + border-radius). Avoid the AI-slop left-accent rounded card; express emphasis through layout, type scale, or color roles instead.",
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
break
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def check_pptx_export_hints(content: str, findings: list[Finding]) -> None:
|
|
331
|
+
# 三层分层现在由导出器 tagLayers **自动完成**(截图前按结构判:离散块→中层逐元素切图、文本→顶层
|
|
332
|
+
# 可编辑框、其余→背景底图)。标注是可选 override,**不再是分层前提**——故**不**再为「没标
|
|
333
|
+
# foreground/text」报警(那在自动分层后是假警报,会诱导模型做无谓标注、甚至把结构图当 AI 图)。
|
|
334
|
+
# 这里只留**真有用**的两条:① 多页 deck 的 [hidden] CSS(预览稳定);② 用 ignore 排除浏览器控件/装饰。
|
|
335
|
+
if re.search(r"\.slide\s*\{[^}]*display\s*:\s*(?:grid|flex|block)", content, re.I | re.S):
|
|
336
|
+
if not re.search(r"\[hidden\]\s*\{[^}]*display\s*:\s*none\s*!important", content, re.I | re.S):
|
|
337
|
+
findings.append(
|
|
338
|
+
Finding(
|
|
339
|
+
"warning",
|
|
340
|
+
"Slide CSS sets display, which can override the HTML hidden attribute. Add [hidden] { display: none !important; } for deck preview stability.",
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# 提示(info,非问题):分层自动;要让某元素**保留烧进底图/不单独编辑**用 data-pptx-export="ignore"。
|
|
345
|
+
if re.search(r"data-screen-label", content) and "data-pptx-export" not in content:
|
|
346
|
+
findings.append(
|
|
347
|
+
Finding(
|
|
348
|
+
"info",
|
|
349
|
+
"Layering is automatic (text → editable top layer, discrete blocks → per-element middle-layer images, the rest → background). No need to tag every element; use data-pptx-layer=\"foreground\" only to force a block, and data-pptx-export=\"ignore\" to keep browser controls / decorative art baked into the background.",
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def check_gradient_over_image(content: str, findings: list[Finding]) -> None:
|
|
355
|
+
# 真机头号事故:deck 写 `.edit-bg{background:<不透明渐变>, url('assets/img.png')}`——CSS 逗号分隔的
|
|
356
|
+
# 多重背景里**靠前的层画在靠后的层之上**,故逗号在 url() 之前的渐变(尤其不透明)会把 AI 背景图整张盖死。
|
|
357
|
+
# 确定性扫描 background/background-image 值中「渐变(linear/radial)在 url() 之前」的写法 → WARNING。
|
|
358
|
+
# 渐变只应进**半透明** .edit-scrim 兜对比,不该和 url 图挤在同一个 background 简写里压在图上面。
|
|
359
|
+
# WARNING 级、不阻断导出(exit code 不变)——与现有 PPTX 导出检查同风格。
|
|
360
|
+
for match in re.finditer(
|
|
361
|
+
r"background[^:]*:\s*[^;]*(?:linear|radial)-gradient[^;]*,\s*url\(",
|
|
362
|
+
content,
|
|
363
|
+
re.I,
|
|
364
|
+
):
|
|
365
|
+
snippet = re.sub(r"\s+", " ", match.group(0).strip())
|
|
366
|
+
if len(snippet) > 120:
|
|
367
|
+
snippet = snippet[:120] + "…"
|
|
368
|
+
findings.append(
|
|
369
|
+
Finding(
|
|
370
|
+
"warning",
|
|
371
|
+
f"渐变写在 url 图之前会盖死背景图,渐变只应进半透明 .edit-scrim(命中:{snippet})",
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def run_checks(path: Path, for_pptx_export: bool = False, require_tweaks: bool = False) -> list[Finding]:
|
|
377
|
+
findings: list[Finding] = []
|
|
378
|
+
if not path.exists():
|
|
379
|
+
return [Finding("error", f"File not found: {path}")]
|
|
380
|
+
if not path.is_file():
|
|
381
|
+
return [Finding("error", f"Path is not a file: {path}")]
|
|
382
|
+
|
|
383
|
+
content = path.read_text(encoding="utf-8")
|
|
384
|
+
check_basic_html(content, findings)
|
|
385
|
+
check_malformed_visible_css(content, findings)
|
|
386
|
+
if "scrollIntoView" in content:
|
|
387
|
+
findings.append(Finding("error", "Do not use scrollIntoView in ui-design artifacts."))
|
|
388
|
+
check_file_size(content, findings)
|
|
389
|
+
check_pinned_scripts(content, findings)
|
|
390
|
+
check_react_babel_structure(content, findings)
|
|
391
|
+
# Tweaks/编辑模式是浏览器内「实时调参」功能;只有原型/变体页明确需要时才强制。
|
|
392
|
+
has_tweaks_markers = "EDITMODE-BEGIN" in content or "EDITMODE-END" in content
|
|
393
|
+
if (require_tweaks or has_tweaks_markers) and not for_pptx_export:
|
|
394
|
+
check_tweaks(content, findings)
|
|
395
|
+
check_deck_and_fixed_size(content, findings, for_pptx_export=for_pptx_export)
|
|
396
|
+
check_speaker_notes(content, findings)
|
|
397
|
+
check_placeholders(content, findings)
|
|
398
|
+
check_visual_risks(content, findings)
|
|
399
|
+
check_overused_font(content, findings)
|
|
400
|
+
check_left_border_accent(content, findings)
|
|
401
|
+
if for_pptx_export:
|
|
402
|
+
check_pptx_export_hints(content, findings)
|
|
403
|
+
check_gradient_over_image(content, findings)
|
|
404
|
+
return findings
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def parse_args() -> argparse.Namespace:
|
|
408
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
409
|
+
parser.add_argument("html_file", help="HTML artifact to inspect.")
|
|
410
|
+
parser.add_argument("--for-pptx-export", action="store_true", help="Show PPTX export layering and editability hints.")
|
|
411
|
+
parser.add_argument("--require-tweaks", action="store_true", help="Require a valid EDITMODE/Tweaks block for prototype or variation artifacts.")
|
|
412
|
+
parser.add_argument("--warnings-as-errors", action="store_true", help="Return non-zero when warnings are present.")
|
|
413
|
+
return parser.parse_args()
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def main() -> int:
|
|
417
|
+
args = parse_args()
|
|
418
|
+
findings = run_checks(Path(args.html_file), for_pptx_export=args.for_pptx_export, require_tweaks=args.require_tweaks)
|
|
419
|
+
errors = [item for item in findings if item.severity == "error"]
|
|
420
|
+
warnings = [item for item in findings if item.severity == "warning"]
|
|
421
|
+
|
|
422
|
+
print(f"ui-design artifact check: {args.html_file}")
|
|
423
|
+
if not findings:
|
|
424
|
+
print("OK: no issues found.")
|
|
425
|
+
else:
|
|
426
|
+
for item in findings:
|
|
427
|
+
print(f"{item.severity.upper()}: {item.message}")
|
|
428
|
+
|
|
429
|
+
if errors or (args.warnings_as_errors and warnings):
|
|
430
|
+
return 1
|
|
431
|
+
return 0
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
if __name__ == "__main__":
|
|
435
|
+
sys.exit(main())
|