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.
- package/README.md +14 -12
- 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 +3 -1
- package/plugins/workflow-runner/src/agentCommon.js +249 -51
- package/plugins/workflow-runner/src/dslManifest.js +72 -0
- package/plugins/workflow-runner/src/expressions.js +198 -15
- package/plugins/workflow-runner/src/index.js +40 -8
- package/plugins/workflow-runner/src/jsonPayload.js +1 -1
- package/plugins/workflow-runner/src/loader.js +286 -72
- package/plugins/workflow-runner/src/multimodal.js +37 -0
- package/plugins/workflow-runner/src/recovery.js +49 -39
- package/plugins/workflow-runner/src/runner.js +802 -287
- package/plugins/workflow-runner/src/stepExecutors/agent.js +157 -39
- package/plugins/workflow-runner/src/stepExecutors/assert.js +16 -3
- package/plugins/workflow-runner/src/stepExecutors/llm.js +60 -111
- package/plugins/workflow-runner/src/stepExecutors/skill.js +47 -47
- package/plugins/workflow-runner/src/stepExecutors/tool.js +76 -10
- package/plugins/workflow-runner/src/stepExecutors/verify.js +27 -10
- package/plugins/workflow-runner/src/taskIdentity.js +296 -0
- package/plugins/workflow-runner/src/types.js +19 -9
- package/plugins/workflow-runner/src/workflowState.js +516 -33
- package/skills/adversarial-review/SKILL.md +0 -1
- 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 +97 -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 +7 -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 +28 -15
- package/src/llm/client.js +394 -159
- package/src/llm/providers/anthropicFormat.js +241 -0
- package/src/llm/providers/openaiFormat.js +190 -0
- package/src/loop.js +219 -32
- 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/pluginLoader.js +2 -1
- package/src/plugins/pluginRunner.js +49 -21
- package/src/plugins/transcript.js +4 -3
- package/src/prompts/pluginList.js +5 -5
- package/src/prompts/projectInstructions.js +3 -3
- package/src/prompts/promptAssembly.js +133 -144
- package/src/prompts/skillList.js +12 -22
- package/src/prompts/system.js +0 -1
- 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 +29 -10
- package/src/ui/InputBox.js +104 -12
- 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 +358 -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 +13 -5
- package/workflows/book-review-short.yaml +36 -10
- package/workflows/e2e-write-greet.yaml +6 -2
- package/workflows/illustrate.yaml +227 -0
- package/workflows/plan.yaml +460 -179
- package/workflows/ppt.yaml +1659 -0
- package/workflows/ralph-loop.yaml +199 -0
- package/workflows/schema.json +81 -23
- package/workflows/webppt.yaml +496 -0
- package/workflows/word.yaml +710 -0
- package/workflows/youtube-shorts.yaml +46 -15
- package/MINIMAL-TRACE.md +0 -77
- package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
- package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
- package/plugins/ralph-wiggum/README.md +0 -197
- package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
- package/plugins/ralph-wiggum/commands/help.md +0 -137
- package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
- package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
- package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
- package/plugins/ralph-wiggum/plugin.js +0 -280
- package/plugins/ralph-wiggum/src/goalState.js +0 -258
- package/plugins/ralph-wiggum/src/sentinels.js +0 -76
- package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
- package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
- package/plugins/workflow-runner/src/miniReAct.js +0 -223
- 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/src/ui/ProgressPanel.js +0 -54
- package/src/ui/StreamingBlock.js +0 -11
- package/src/ui/ToolStatus.js +0 -11
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
image_plan_lint.py —— 配图分流确定性闸门:拦下「本该用 HTML/SVG 画的结构图」被当 AI 图生成。
|
|
5
|
+
|
|
6
|
+
为什么需要这个脚本?
|
|
7
|
+
====================
|
|
8
|
+
`/workflow ppt` 里弱/懒模型有个固定偷懒模式:把**结构图**(流程图、架构图、分层图、树状图/决策树、
|
|
9
|
+
并轨/对比图)**改名成"抽象概念背景 / 章节氛围图"**塞进 `route=ai-A/ai-B`,用 AI 生成。真机产物
|
|
10
|
+
`build_bak/` 实证:img_2「architecture visualization with 5 layers」、img_3「parallel tracks」、
|
|
11
|
+
img_5「decision tree」全是 AI 生的结构图。AI 渲染结构**必糊、必错、无文字、不可编辑**——而 HTML/SVG
|
|
12
|
+
精确、可编辑、零成本。`layout-composition.md` 早已写"流程图/架构图→用 HTML",但纯提示词规则被绕过了,
|
|
13
|
+
所以需要一道**绕不过的确定性闸门**(与 layout_balance.py / check_ui_artifact.py 同哲学,作用在生图计划上)。
|
|
14
|
+
|
|
15
|
+
它查什么?
|
|
16
|
+
==========
|
|
17
|
+
扫 `img_plan.json` 里 **text-to-image** 条的 `prompt`(英)+(可选)`design.json` / `outline.json` 里
|
|
18
|
+
`route=ai-A/ai-B` 页的 `visual.note`(中),命中**精挑的双语「图表型名词」黑名单**(architecture /
|
|
19
|
+
flowchart / decision tree / parallel tracks / 架构 / 流程图 / 决策树 / 双轨 …)即判违规 → 那张应改用
|
|
20
|
+
HTML/SVG,不要 AI 生成。
|
|
21
|
+
|
|
22
|
+
**只查「AI 凭空生成」,不碰真实客户图**:`image-to-image` 提示词 / `source-enhanced` 路由处理的是
|
|
23
|
+
**客户真图的 img2img 增强**(提示词保原内容),其结构是客户真图带来的、不是 AI 造的——一律豁免结构/审美检查。
|
|
24
|
+
否则会把「客户提供的对比图/架构图 direct_contain 原比例」误判成违规,逼着删 img_plan / 改 HTML,
|
|
25
|
+
反而丢弃真实客户图(违红线「客户图 contain 用 as-is」)。要不要把某结构 HTML 化是设计取舍,不在本闸门硬拦。
|
|
26
|
+
|
|
27
|
+
**刻意不封堵**装饰性 / 设计性词(nodes、lines、geometric、gradient、单独的 network、visual hierarchy、
|
|
28
|
+
contrast/对比色、bare "layers/分层")——它们在合法氛围图里也常见。已用 build_bak 反向校准:净命中
|
|
29
|
+
img_2/3/5(真结构图),放行 img_1(封面渐变氛围)/ img_4(山峰隐喻)。
|
|
30
|
+
|
|
31
|
+
诚实边界(不静默夸大)
|
|
32
|
+
======================
|
|
33
|
+
本闸门只抓**自报式**结构 prompt/note(直接写了图表名词的)。若模型改写措辞规避("five stacked
|
|
34
|
+
horizontal bands" 而非 "5 layers"),关键词匹配抓不到——那一层仍靠 layout-composition.md 的 guidance
|
|
35
|
+
(AI 背景只能氛围/隐喻、不得承载可命名结构)。两层配合,不是单靠本脚本。
|
|
36
|
+
|
|
37
|
+
和 layout_balance / opc_check 一样:只用标准库(json / argparse / os / sys),不替代视觉 QA。
|
|
38
|
+
|
|
39
|
+
退出码:0 = 通过(或无 img_plan.json,无需检查);1 = 发现违规;2 = 参数 / 解析错。
|
|
40
|
+
|
|
41
|
+
用法
|
|
42
|
+
====
|
|
43
|
+
python image_plan_lint.py ./build/img_plan.json [--outline ./build/design.json] [-v]
|
|
44
|
+
python image_plan_lint.py ./build # 传目录则自动找 img_plan.json / design.json / outline.json
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
import argparse
|
|
48
|
+
import json
|
|
49
|
+
import os
|
|
50
|
+
import re
|
|
51
|
+
import sys
|
|
52
|
+
|
|
53
|
+
# 「图表型名词」黑名单 —— 命中即「这是结构图,应 HTML/SVG,不该 AI 生」。
|
|
54
|
+
# 选词原则:只收**自报式图表名词**(diagram-type nouns),刻意排除装饰/设计词以免误伤氛围图。
|
|
55
|
+
# 大小写不敏感(统一 .lower() 后子串匹配);中英混在一张表,对 prompt 与 note 同样适用。
|
|
56
|
+
STRUCTURAL_TERMS = [
|
|
57
|
+
# —— 英文(多为 img_plan.prompt)——
|
|
58
|
+
"architecture", # architecture diagram / visualization(系统架构图)
|
|
59
|
+
"flowchart",
|
|
60
|
+
"flow chart",
|
|
61
|
+
"flow diagram",
|
|
62
|
+
"process diagram",
|
|
63
|
+
"decision tree",
|
|
64
|
+
"tree diagram",
|
|
65
|
+
"org chart",
|
|
66
|
+
"organizational chart",
|
|
67
|
+
"hierarchy diagram", # 注意:不收裸 "hierarchy"("visual hierarchy" 是合法构图术语)
|
|
68
|
+
"mind map",
|
|
69
|
+
"layered architecture", # 不收裸 "layers"("layers of light/mist" 是合法氛围)
|
|
70
|
+
"layered structure",
|
|
71
|
+
"parallel paths",
|
|
72
|
+
"parallel tracks",
|
|
73
|
+
"parallel evolution",
|
|
74
|
+
"parallel lanes",
|
|
75
|
+
"swimlane",
|
|
76
|
+
"topology",
|
|
77
|
+
"network diagram", # 不收裸 "network"("neural network nodes" 装饰底图合法)
|
|
78
|
+
"comparison chart",
|
|
79
|
+
"comparison matrix", # 不收裸 "comparison/contrast"("对比色/contrast" 是配色术语)
|
|
80
|
+
"gantt",
|
|
81
|
+
"timeline",
|
|
82
|
+
"data flow",
|
|
83
|
+
# —— 中文(多为 outline.visual.note)——
|
|
84
|
+
"架构", # 架构图 / 架构示意 / 五层架构(实物"建筑架构"罕见于科技配图,命中后可人工豁免)
|
|
85
|
+
"流程图",
|
|
86
|
+
"流程",
|
|
87
|
+
"步骤图",
|
|
88
|
+
"决策树",
|
|
89
|
+
"树状",
|
|
90
|
+
"树形",
|
|
91
|
+
"组织结构",
|
|
92
|
+
"层级",
|
|
93
|
+
"思维导图",
|
|
94
|
+
"时间线",
|
|
95
|
+
"时间轴",
|
|
96
|
+
"关系图",
|
|
97
|
+
"拓扑",
|
|
98
|
+
"对比图",
|
|
99
|
+
"对比矩阵",
|
|
100
|
+
"矩阵图",
|
|
101
|
+
"并轨",
|
|
102
|
+
"双轨",
|
|
103
|
+
"泳道",
|
|
104
|
+
"数据流",
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
HINT = "改用 HTML/SVG 表达结构,不要 AI 生成"
|
|
108
|
+
|
|
109
|
+
# 这些词不一定是结构图,但会稳定诱发「廉价科技底图 / 盾牌跑偏 / 拼贴缩略图 / UI 卡片墙」。
|
|
110
|
+
# 产品详情页式 PPT 的 AI 图应是摄影感场景、产品/设备特写、低干扰背景或完整客户图增强,
|
|
111
|
+
# 而不是把页面结构、卡片或小图阵列直接交给生图模型。
|
|
112
|
+
BAD_AESTHETIC_TERMS = [
|
|
113
|
+
"abstract blueprint",
|
|
114
|
+
"blueprint background",
|
|
115
|
+
"crosshair",
|
|
116
|
+
"target reticle",
|
|
117
|
+
"shield",
|
|
118
|
+
"aegis",
|
|
119
|
+
"18 thumbnails",
|
|
120
|
+
"thumbnail grid",
|
|
121
|
+
"many thumbnails",
|
|
122
|
+
"ui card",
|
|
123
|
+
"ui cards",
|
|
124
|
+
"floating cards",
|
|
125
|
+
"dashboard cards",
|
|
126
|
+
"matrix background",
|
|
127
|
+
"collage of icons",
|
|
128
|
+
"text label",
|
|
129
|
+
"准星",
|
|
130
|
+
"靶心",
|
|
131
|
+
"盾牌",
|
|
132
|
+
"缩略图",
|
|
133
|
+
"卡片墙",
|
|
134
|
+
"浮动卡片",
|
|
135
|
+
"矩阵背景",
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
BAD_AESTHETIC_HINT = "改成摄影感场景/完整产品特写/低干扰背景;不要让 AI 画卡片、盾牌、准星或缩略图阵列"
|
|
139
|
+
|
|
140
|
+
I2I_ONLY_TERMS = [
|
|
141
|
+
"use the attached image",
|
|
142
|
+
"attached image",
|
|
143
|
+
"strict visual reference",
|
|
144
|
+
"preserve its main subject",
|
|
145
|
+
"preserve its main subject, content and real colors",
|
|
146
|
+
"input image",
|
|
147
|
+
"source_file",
|
|
148
|
+
"source image",
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
I2I_ONLY_HINT = "这是图生图提示词,不能用于 text-to-image 背景;改成独立互补背景/场景 prompt"
|
|
152
|
+
|
|
153
|
+
# 这些词经常让文生图跑成随机消费电子、游戏手柄、药瓶/化妆瓶、普通显示器。
|
|
154
|
+
# 如果没有同时出现从当前 design/outline 动态抽出的业务锚点,就说明 prompt 没有和 PPT 文案绑定。
|
|
155
|
+
GENERIC_OBJECT_RISK_TERMS = [
|
|
156
|
+
"professional product photography",
|
|
157
|
+
"sleek device",
|
|
158
|
+
"futuristic screen",
|
|
159
|
+
"generic consumer device",
|
|
160
|
+
"generic monitor",
|
|
161
|
+
"random monitor",
|
|
162
|
+
"game controller",
|
|
163
|
+
"cosmetic bottle",
|
|
164
|
+
"medicine bottle",
|
|
165
|
+
"shampoo bottle",
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
GENERIC_OBJECT_HINT = "文生图 prompt 太泛或含随机消费品风险;必须绑定页面标题/结论/行业场景/VI,并排除手柄、瓶子、普通显示器等无关物体"
|
|
169
|
+
|
|
170
|
+
BACKGROUND_TEXT_MARKER_TERMS = [
|
|
171
|
+
"chapter number",
|
|
172
|
+
"chapter numbers",
|
|
173
|
+
"numbered chapters",
|
|
174
|
+
"numbers 1 2 3 4",
|
|
175
|
+
"sequence numbers",
|
|
176
|
+
"text labels",
|
|
177
|
+
"labels on the image",
|
|
178
|
+
"captions in the image",
|
|
179
|
+
"章节序号",
|
|
180
|
+
"章节编号",
|
|
181
|
+
"序号",
|
|
182
|
+
"编号",
|
|
183
|
+
"数字标签",
|
|
184
|
+
"文字标签",
|
|
185
|
+
"图中文字",
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
BACKGROUND_TEXT_MARKER_HINT = "背景/场景/hero 图不得生成不可编辑文字、数字、标签或章节序号;这些必须用 HTML/SVG 前景可编辑元素实现"
|
|
189
|
+
|
|
190
|
+
# 背景层 t2i 提示词不得携带页面文案/图表描述(2026-07-03 ai_p9 真机事故:rewrite 曾把
|
|
191
|
+
# "Slide title: 投入有限,对冲无限. Core message: 核心总投入约 3 万元… Visual focus: 成本拆解 HTML 表 +
|
|
192
|
+
# 投入/对冲对比柱状图" 原文拼进背景 t2i prompt——Seedream 类文字渲染型模型照着画出一整版烘字假幻灯片,
|
|
193
|
+
# 与 HTML 真表格/真图表互相遮挡)。只对 target=background 的 text-to-image 生效;前景 cutout 模板
|
|
194
|
+
# 合法使用 "Topic anchors:",i2i(客户图增强)一律豁免。
|
|
195
|
+
SLIDE_COPY_MARKER_TERMS = [
|
|
196
|
+
"slide title:",
|
|
197
|
+
"core message:",
|
|
198
|
+
"topic anchors:",
|
|
199
|
+
"柱状图",
|
|
200
|
+
"折线图",
|
|
201
|
+
"饼图",
|
|
202
|
+
"表格",
|
|
203
|
+
"数据表",
|
|
204
|
+
"bar chart",
|
|
205
|
+
"line chart",
|
|
206
|
+
"pie chart",
|
|
207
|
+
"data table",
|
|
208
|
+
"cost breakdown",
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
SLIDE_COPY_HINT = (
|
|
212
|
+
"背景生图提示词不得携带页标题/正文句/图表描述——文字渲染型生图模型会照着画出整版烘字假幻灯片;"
|
|
213
|
+
"背景只写场景/材质/光线/留白,标题正文由 HTML 文字层承载、表格图表由 HTML/SVG 层绘制"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
NEGATION_RE = re.compile(
|
|
217
|
+
r"(?:\bno\b|\bwithout\b|\bdo\s+not\b|\bdon't\b|\bavoid\b|\bnever\b|\bnot\s+a\b|\bnot\s+an\b|"
|
|
218
|
+
r"禁止|不要|不得|不生成|不画|不出现|避免|不能|不可)",
|
|
219
|
+
re.I,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
CHINESE_ANCHOR_RE = re.compile(r"[\u4e00-\u9fff][\u4e00-\u9fffA-Za-z0-9·+\-/]{1,11}")
|
|
223
|
+
ENGLISH_ANCHOR_RE = re.compile(r"\b[A-Za-z][A-Za-z0-9+\-/]{3,}\b")
|
|
224
|
+
ANCHOR_STOPWORDS = {
|
|
225
|
+
"主题", "用户", "要求", "生成", "做成", "页面", "背景", "图片", "文字", "内容", "设计",
|
|
226
|
+
"视觉", "风格", "中文", "文案", "标题", "素材", "客户", "产品", "场景", "重点", "需要",
|
|
227
|
+
"必须", "用于", "高清", "比例", "信息", "专业", "方案", "系统", "能力", "价值", "结构",
|
|
228
|
+
"presentation", "visual", "image", "slide", "title", "core", "message", "premium",
|
|
229
|
+
"product", "detail", "page", "background", "foreground", "style", "clean", "high",
|
|
230
|
+
"resolution", "text", "safe", "zone",
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _find_terms(text):
|
|
235
|
+
"""返回 text 命中的黑名单词列表(去重、保序);text 非字符串或空 → []。"""
|
|
236
|
+
return _find_non_negated_terms(text, STRUCTURAL_TERMS)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _find_bad_aesthetic_terms(text):
|
|
240
|
+
return _find_non_negated_terms(text, BAD_AESTHETIC_TERMS)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _find_i2i_only_terms(text):
|
|
244
|
+
if not isinstance(text, str) or not text:
|
|
245
|
+
return []
|
|
246
|
+
hay = text.lower()
|
|
247
|
+
hits = []
|
|
248
|
+
for term in I2I_ONLY_TERMS:
|
|
249
|
+
if term.lower() in hay and term not in hits:
|
|
250
|
+
hits.append(term)
|
|
251
|
+
return hits
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _is_negated_match(text, start):
|
|
255
|
+
"""Return True when a matched risky term is inside a nearby negative constraint.
|
|
256
|
+
|
|
257
|
+
Image prompts deliberately include constraints such as "no game controller" and
|
|
258
|
+
"do not create a thumbnail grid". Those should not be treated as positive
|
|
259
|
+
requests to generate the banned object/layout.
|
|
260
|
+
"""
|
|
261
|
+
prefix = text[max(0, start - 48):start]
|
|
262
|
+
return bool(NEGATION_RE.search(prefix))
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _find_non_negated_terms(text, terms):
|
|
266
|
+
if not isinstance(text, str) or not text:
|
|
267
|
+
return []
|
|
268
|
+
hay = text.lower()
|
|
269
|
+
hits = []
|
|
270
|
+
for term in terms:
|
|
271
|
+
needle = term.lower()
|
|
272
|
+
pos = hay.find(needle)
|
|
273
|
+
while pos >= 0:
|
|
274
|
+
if not _is_negated_match(text, pos):
|
|
275
|
+
if term not in hits:
|
|
276
|
+
hits.append(term)
|
|
277
|
+
break
|
|
278
|
+
pos = hay.find(needle, pos + len(needle))
|
|
279
|
+
return hits
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _text_of(value):
|
|
283
|
+
if value is None:
|
|
284
|
+
return ""
|
|
285
|
+
if isinstance(value, str):
|
|
286
|
+
return value
|
|
287
|
+
if isinstance(value, (int, float, bool)):
|
|
288
|
+
return str(value)
|
|
289
|
+
if isinstance(value, list):
|
|
290
|
+
return " ".join(_text_of(v) for v in value)
|
|
291
|
+
if isinstance(value, dict):
|
|
292
|
+
return " ".join(_text_of(v) for v in value.values())
|
|
293
|
+
return str(value)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _add_anchor(out, value):
|
|
297
|
+
value = value.strip(" ,,。.;;::()()[]【】<>《》\"'")
|
|
298
|
+
if len(value) < 2:
|
|
299
|
+
return
|
|
300
|
+
if value.lower() in ANCHOR_STOPWORDS:
|
|
301
|
+
return
|
|
302
|
+
if value not in out:
|
|
303
|
+
out.append(value)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _extract_dynamic_anchors(value, limit=80):
|
|
307
|
+
text = _text_of(value)
|
|
308
|
+
anchors = []
|
|
309
|
+
for match in CHINESE_ANCHOR_RE.findall(text):
|
|
310
|
+
_add_anchor(anchors, match)
|
|
311
|
+
if len(anchors) >= limit:
|
|
312
|
+
return anchors
|
|
313
|
+
for match in ENGLISH_ANCHOR_RE.findall(text):
|
|
314
|
+
_add_anchor(anchors, match)
|
|
315
|
+
if len(anchors) >= limit:
|
|
316
|
+
return anchors
|
|
317
|
+
return anchors
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _find_generic_object_risks(text, anchors=None):
|
|
321
|
+
if not isinstance(text, str) or not text:
|
|
322
|
+
return []
|
|
323
|
+
anchors = anchors or []
|
|
324
|
+
hay = text.lower()
|
|
325
|
+
hits = _find_non_negated_terms(text, GENERIC_OBJECT_RISK_TERMS)
|
|
326
|
+
if not hits:
|
|
327
|
+
return []
|
|
328
|
+
explicit_bad = [
|
|
329
|
+
term for term in hits
|
|
330
|
+
if term in ("game controller", "cosmetic bottle", "medicine bottle", "shampoo bottle", "generic monitor", "random monitor")
|
|
331
|
+
]
|
|
332
|
+
has_anchor = any(str(term).lower() in hay for term in anchors)
|
|
333
|
+
return hits if explicit_bad or not has_anchor else []
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _find_background_text_marker_terms(text):
|
|
337
|
+
return _find_non_negated_terms(text, BACKGROUND_TEXT_MARKER_TERMS)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _find_slide_copy_terms(text):
|
|
341
|
+
return _find_non_negated_terms(text, SLIDE_COPY_MARKER_TERMS)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _is_background_target(item):
|
|
345
|
+
"""镜像 image_prompt_rewrite 的背景判定:`_fg.` 文件名或 role/target_layer 声明前景 → 非背景。"""
|
|
346
|
+
file_name = str(item.get("file") or "").lower()
|
|
347
|
+
if "_fg." in file_name:
|
|
348
|
+
return False
|
|
349
|
+
role = str(item.get("role") or item.get("target_layer") or "").lower()
|
|
350
|
+
return role not in ("foreground", "fg", "cutout")
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _snippet(text, terms, width=80):
|
|
354
|
+
"""截取首个命中词附近的一小段原文,便于人读定位(不回显整段长 prompt)。"""
|
|
355
|
+
if not isinstance(text, str):
|
|
356
|
+
return ""
|
|
357
|
+
low = text.lower()
|
|
358
|
+
pos = min((low.find(t.lower()) for t in terms if t.lower() in low), default=-1)
|
|
359
|
+
if pos < 0:
|
|
360
|
+
return text[:width].strip()
|
|
361
|
+
start = max(0, pos - 16)
|
|
362
|
+
return text[start:start + width].strip()
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _resolve(path, filename):
|
|
366
|
+
"""path 是目录则拼 filename;是文件则原样返回。不存在交由调用方处理。"""
|
|
367
|
+
if path and os.path.isdir(path):
|
|
368
|
+
return os.path.join(path, filename)
|
|
369
|
+
return path
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def lint(img_plan_path, outline_path=None):
|
|
373
|
+
"""
|
|
374
|
+
返回 (violations, scanned, plan_exists):
|
|
375
|
+
violations = [{"where","id","terms","snippet"}, ...]
|
|
376
|
+
scanned = 实际扫了几条(prompt 条数 + ai-* note 数)
|
|
377
|
+
plan_exists= img_plan.json 是否存在(不存在 = 无需检查,视为通过)
|
|
378
|
+
解析失败抛 ValueError(main 转 exit 2)。
|
|
379
|
+
"""
|
|
380
|
+
violations = []
|
|
381
|
+
scanned = 0
|
|
382
|
+
outline = None
|
|
383
|
+
dynamic_anchors = []
|
|
384
|
+
|
|
385
|
+
if outline_path and os.path.isfile(outline_path):
|
|
386
|
+
try:
|
|
387
|
+
with open(outline_path, "r", encoding="utf-8") as f:
|
|
388
|
+
outline = json.load(f)
|
|
389
|
+
dynamic_anchors = _extract_dynamic_anchors(outline)
|
|
390
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
391
|
+
raise ValueError(f"读取/解析 {outline_path} 失败:{e}")
|
|
392
|
+
|
|
393
|
+
# —— 1. img_plan.json 的每条 prompt(精确到 file)——
|
|
394
|
+
plan_exists = bool(img_plan_path) and os.path.isfile(img_plan_path)
|
|
395
|
+
if plan_exists:
|
|
396
|
+
try:
|
|
397
|
+
with open(img_plan_path, "r", encoding="utf-8") as f:
|
|
398
|
+
plan = json.load(f)
|
|
399
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
400
|
+
raise ValueError(f"读取/解析 {img_plan_path} 失败:{e}")
|
|
401
|
+
if not isinstance(plan, list):
|
|
402
|
+
raise ValueError(f"{img_plan_path} 应是数组(每条 {{file,aspect,prompt}}),实际是 {type(plan).__name__}")
|
|
403
|
+
for i, item in enumerate(plan):
|
|
404
|
+
if not isinstance(item, dict):
|
|
405
|
+
continue
|
|
406
|
+
prompt = item.get("prompt", "")
|
|
407
|
+
mode = str(item.get("mode") or "text-to-image").lower()
|
|
408
|
+
scanned += 1
|
|
409
|
+
# 结构词/坏审美是「AI 凭空造图」检查,只对 text-to-image 生效;image-to-image 增强的是
|
|
410
|
+
# 真实客户图(提示词保原内容),其结构/审美是客户真图带来的、不是 AI 造的 → 豁免
|
|
411
|
+
# (与下方 i2i/generic/marker 的 mode 守卫同一逻辑)。无 mode 字段默认 text-to-image。
|
|
412
|
+
terms = _find_terms(prompt) if mode != "image-to-image" else []
|
|
413
|
+
if terms:
|
|
414
|
+
violations.append({
|
|
415
|
+
"where": "img_plan.prompt",
|
|
416
|
+
"id": str(item.get("file", f"#{i}")),
|
|
417
|
+
"terms": terms,
|
|
418
|
+
"snippet": _snippet(prompt, terms),
|
|
419
|
+
"hint": HINT,
|
|
420
|
+
})
|
|
421
|
+
bad_terms = _find_bad_aesthetic_terms(prompt) if mode != "image-to-image" else []
|
|
422
|
+
if bad_terms:
|
|
423
|
+
violations.append({
|
|
424
|
+
"where": "img_plan.prompt",
|
|
425
|
+
"id": str(item.get("file", f"#{i}")),
|
|
426
|
+
"terms": bad_terms,
|
|
427
|
+
"snippet": _snippet(prompt, bad_terms),
|
|
428
|
+
"hint": BAD_AESTHETIC_HINT,
|
|
429
|
+
})
|
|
430
|
+
i2i_terms = _find_i2i_only_terms(prompt) if mode != "image-to-image" else []
|
|
431
|
+
if i2i_terms:
|
|
432
|
+
violations.append({
|
|
433
|
+
"where": "img_plan.prompt",
|
|
434
|
+
"id": str(item.get("file", f"#{i}")),
|
|
435
|
+
"terms": i2i_terms,
|
|
436
|
+
"snippet": _snippet(prompt, i2i_terms),
|
|
437
|
+
"hint": I2I_ONLY_HINT,
|
|
438
|
+
})
|
|
439
|
+
generic_terms = _find_generic_object_risks(prompt, dynamic_anchors) if mode != "image-to-image" else []
|
|
440
|
+
if generic_terms:
|
|
441
|
+
violations.append({
|
|
442
|
+
"where": "img_plan.prompt",
|
|
443
|
+
"id": str(item.get("file", f"#{i}")),
|
|
444
|
+
"terms": generic_terms,
|
|
445
|
+
"snippet": _snippet(prompt, generic_terms),
|
|
446
|
+
"hint": GENERIC_OBJECT_HINT,
|
|
447
|
+
})
|
|
448
|
+
marker_terms = _find_background_text_marker_terms(prompt) if mode != "image-to-image" else []
|
|
449
|
+
if marker_terms:
|
|
450
|
+
violations.append({
|
|
451
|
+
"where": "img_plan.prompt",
|
|
452
|
+
"id": str(item.get("file", f"#{i}")),
|
|
453
|
+
"terms": marker_terms,
|
|
454
|
+
"snippet": _snippet(prompt, marker_terms),
|
|
455
|
+
"hint": BACKGROUND_TEXT_MARKER_HINT,
|
|
456
|
+
})
|
|
457
|
+
slide_copy_terms = (
|
|
458
|
+
_find_slide_copy_terms(prompt)
|
|
459
|
+
if mode != "image-to-image" and _is_background_target(item)
|
|
460
|
+
else []
|
|
461
|
+
)
|
|
462
|
+
if slide_copy_terms:
|
|
463
|
+
violations.append({
|
|
464
|
+
"where": "img_plan.prompt",
|
|
465
|
+
"id": str(item.get("file", f"#{i}")),
|
|
466
|
+
"terms": slide_copy_terms,
|
|
467
|
+
"snippet": _snippet(prompt, slide_copy_terms),
|
|
468
|
+
"hint": SLIDE_COPY_HINT,
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
# —— 2.(可选)outline.json 里 route=ai-A/ai-B/source-enhanced 页的 visual.note(精确到 page,提召回)——
|
|
472
|
+
if outline_path and os.path.isfile(outline_path):
|
|
473
|
+
pages = outline.get("pages", []) if isinstance(outline, dict) else []
|
|
474
|
+
for p in pages:
|
|
475
|
+
if not isinstance(p, dict):
|
|
476
|
+
continue
|
|
477
|
+
visual = p.get("visual", {}) if isinstance(p.get("visual"), dict) else {}
|
|
478
|
+
route = str(visual.get("route", "")).lower()
|
|
479
|
+
# 只扫「AI 凭空生成」的路由。source-enhanced(客户图 img2img 增强)是**真实客户内容**——
|
|
480
|
+
# 结构由客户真图承载(img2img 保原图),note 里出现「对比图/架构」是描述真图、不是 AI 造结构,
|
|
481
|
+
# 扫它会误伤合法客户图并逼「删 img_plan / 改 HTML」丢弃真图(违红线「客户图 contain 用 as-is」)。
|
|
482
|
+
if route not in ("ai-a", "ai-b"):
|
|
483
|
+
continue
|
|
484
|
+
note = visual.get("note", "")
|
|
485
|
+
scanned += 1
|
|
486
|
+
terms = _find_terms(note)
|
|
487
|
+
if terms:
|
|
488
|
+
violations.append({
|
|
489
|
+
"where": "outline.visual.note",
|
|
490
|
+
"id": f"page {p.get('page', '?')}({p.get('title', '')})",
|
|
491
|
+
"terms": terms,
|
|
492
|
+
"snippet": _snippet(note, terms),
|
|
493
|
+
"hint": HINT,
|
|
494
|
+
})
|
|
495
|
+
bad_terms = _find_bad_aesthetic_terms(note)
|
|
496
|
+
if bad_terms:
|
|
497
|
+
violations.append({
|
|
498
|
+
"where": "outline.visual.note",
|
|
499
|
+
"id": f"page {p.get('page', '?')}({p.get('title', '')})",
|
|
500
|
+
"terms": bad_terms,
|
|
501
|
+
"snippet": _snippet(note, bad_terms),
|
|
502
|
+
"hint": BAD_AESTHETIC_HINT,
|
|
503
|
+
})
|
|
504
|
+
marker_terms = _find_background_text_marker_terms(note)
|
|
505
|
+
if marker_terms:
|
|
506
|
+
violations.append({
|
|
507
|
+
"where": "outline.visual.note",
|
|
508
|
+
"id": f"page {p.get('page', '?')}({p.get('title', '')})",
|
|
509
|
+
"terms": marker_terms,
|
|
510
|
+
"snippet": _snippet(note, marker_terms),
|
|
511
|
+
"hint": BACKGROUND_TEXT_MARKER_HINT,
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
return violations, scanned, plan_exists
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def main():
|
|
518
|
+
parser = argparse.ArgumentParser(
|
|
519
|
+
description="配图分流确定性闸门:拦下本该 HTML/SVG 的结构图被当 AI 图生成(仅标准库)"
|
|
520
|
+
)
|
|
521
|
+
parser.add_argument(
|
|
522
|
+
"img_plan",
|
|
523
|
+
help="img_plan.json 路径,或其所在目录(目录则自动找 img_plan.json / design.json / outline.json)",
|
|
524
|
+
)
|
|
525
|
+
parser.add_argument("--outline", default=None, help="design.json / outline.json 路径(交叉扫 ai-* 页 visual.note 提召回)")
|
|
526
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="打印扫描条数等明细")
|
|
527
|
+
args = parser.parse_args()
|
|
528
|
+
|
|
529
|
+
img_plan_path = _resolve(args.img_plan, "img_plan.json")
|
|
530
|
+
outline_path = args.outline
|
|
531
|
+
if outline_path is None and args.img_plan and os.path.isdir(args.img_plan):
|
|
532
|
+
for name in ("design.json", "outline.json"):
|
|
533
|
+
cand = os.path.join(args.img_plan, name)
|
|
534
|
+
if os.path.isfile(cand):
|
|
535
|
+
outline_path = cand
|
|
536
|
+
break
|
|
537
|
+
|
|
538
|
+
try:
|
|
539
|
+
violations, scanned, plan_exists = lint(img_plan_path, outline_path)
|
|
540
|
+
except ValueError as e:
|
|
541
|
+
print(f"错误:{e}", file=sys.stderr)
|
|
542
|
+
return 2
|
|
543
|
+
|
|
544
|
+
if not plan_exists:
|
|
545
|
+
# 无 img_plan.json(illustrations=0 / 无 AI 页)= 没有 AI 图要查,直接通过。
|
|
546
|
+
print(f"配图分流检查 PASSED —— 未找到 {img_plan_path}(无 AI 图计划,无需检查)。")
|
|
547
|
+
return 0
|
|
548
|
+
|
|
549
|
+
if args.verbose:
|
|
550
|
+
print(f"已扫描 {scanned} 处(img_plan prompt + outline ai-* note)。")
|
|
551
|
+
|
|
552
|
+
if violations:
|
|
553
|
+
print(f"配图分流检查 FAILED —— 发现 {len(violations)} 处 AI 配图计划风险:")
|
|
554
|
+
for v in violations:
|
|
555
|
+
print(f" - 【{v['where']}】{v['id']} · 命中 {v['terms']} · {v.get('hint') or HINT}")
|
|
556
|
+
if args.verbose and v["snippet"]:
|
|
557
|
+
print(f" ↳ 原文片段:{v['snippet']}")
|
|
558
|
+
print(
|
|
559
|
+
"说明:流程/架构/分层/树/决策树/并轨/对比等**结构图**应用 HTML/SVG 精确绘制(可编辑、不糊、能带文字),"
|
|
560
|
+
"不要让 AI 生成——把这些页 route 改 html、在 deck.html 用 div+CSS Grid / SVG 画结构,并从 img_plan.json 删掉该条。"
|
|
561
|
+
"封面/章节的**纯氛围/隐喻底图**仍可 AI 生(prompt 去掉结构名词即可)。"
|
|
562
|
+
"(本闸门只抓自报式结构 prompt/note,措辞规避仍靠 layout-composition.md 的配图分流 guidance。)"
|
|
563
|
+
)
|
|
564
|
+
return 1
|
|
565
|
+
|
|
566
|
+
print(f"配图分流检查 PASSED —— {img_plan_path} 的 AI 图均为氛围/隐喻/实物,无结构图滥用。")
|
|
567
|
+
return 0
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
if __name__ == "__main__":
|
|
571
|
+
sys.exit(main())
|