@hybridlabor-api/aos 4.6.5 → 4.7.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/.agents/agents.md +1 -0
- package/.agents/nodes.json +5 -1
- package/.agents/state.schema.json +2 -1
- package/.agents/vendor-manifest.json +50 -0
- package/.claude/agents/architect.md +4 -0
- package/.claude/agents/security-reviewer.md +1 -1
- package/.claude/hooks/memb-inject.mjs +257 -135
- package/.claude/hooks/trail-relay.mjs +18 -0
- package/.claude/settings.json +70 -0
- package/.claude/workflows/startcycle-dispatch.mjs +29 -1
- package/.opencode/agents/architect.md +4 -0
- package/.opencode/plugins/bdb-aos.js +75 -0
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/bin/aos-config.mjs +3 -1
- package/bin/aos-uninstall.mjs +55 -1
- package/docs/handover/agenttrail-for-ao.md +58 -0
- package/docs/handover/deja-for-ao.md +51 -0
- package/installer.js +257 -56
- package/mcp_config.json +4 -0
- package/mcps/mcsc/README.md +24 -0
- package/mcps/mcsc/package-lock.json +1234 -0
- package/mcps/mcsc/package.json +14 -0
- package/mcps/mcsc/packages/core/bin/mcsc.js +162 -0
- package/mcps/mcsc/packages/core/rulebook.default.yaml +49 -0
- package/mcps/mcsc/packages/core/schema/rulebook.schema.json +56 -0
- package/mcps/mcsc/packages/core/src/adapters/agy.js +107 -0
- package/mcps/mcsc/packages/core/src/adapters/codex.js +56 -0
- package/mcps/mcsc/packages/core/src/adapters/native.js +14 -0
- package/mcps/mcsc/packages/core/src/adapters/opencode.js +183 -0
- package/mcps/mcsc/packages/core/src/adapters/types.js +21 -0
- package/mcps/mcsc/packages/core/src/capabilities/buildOfferTable.js +34 -0
- package/mcps/mcsc/packages/core/src/capabilities/registry.js +99 -0
- package/mcps/mcsc/packages/core/src/capabilities/types.js +24 -0
- package/mcps/mcsc/packages/core/src/detect/cache.js +47 -0
- package/mcps/mcsc/packages/core/src/detect/inventory.js +73 -0
- package/mcps/mcsc/packages/core/src/detect/probes.js +158 -0
- package/mcps/mcsc/packages/core/src/detect/types.js +26 -0
- package/mcps/mcsc/packages/core/src/rulebook/load.js +53 -0
- package/mcps/mcsc/packages/core/src/rulebook/resolve.js +227 -0
- package/mcps/mcsc/packages/core/src/rulebook/rulebook.types.js +89 -0
- package/mcps/mcsc/packages/core/src/trail.js +17 -0
- package/mcps/mcsc/packages/mcp/server.js +302 -0
- package/mcps/mcsc/server.js +2 -0
- package/package.json +3 -1
- package/skills/basic/bdbmediastorm/SKILL.md +1 -1
- package/skills/basic/godmode-ui-ux/SKILL.md +2 -2
- package/skills/basic/godmode-ui-ux/references/anti-slop-rules.md +44 -40
- package/skills/basic/godmode-ui-ux/references/taste-archetypes.md +49 -0
- package/skills/basic/startcycle/SKILL.md +7 -0
- package/skills/basic/startcycle-graph/SKILL.md +12 -0
- package/skills/basic/startcycle-graph-user/SKILL.md +3 -0
- package/skills/basic/teamwork-preview/SKILL.md +2 -0
- package/skills/bdbrainstorm/SKILL.md +1 -0
- package/skills/global_config/agenttrail/LICENSE +21 -0
- package/skills/global_config/agenttrail/SKILL.md +48 -0
- package/skills/global_config/agenttrail/bin/agenttrail.mjs +1002 -0
- package/skills/global_config/agenttrail/public/index.html +661 -0
- package/skills/global_config/aos-project-init/SKILL.md +25 -5
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +11 -0
- package/skills/global_config/aos-setup/SKILL.md +34 -1
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +115 -1
- package/skills/global_config/archify/LICENSE +22 -0
- package/skills/global_config/archify/SKILL.md +140 -0
- package/skills/global_config/archify/THIRD_PARTY_NOTICES.md +69 -0
- package/skills/global_config/archify/assets/JetBrainsMono-OFL.txt +93 -0
- package/skills/global_config/archify/assets/template.html +14937 -0
- package/skills/global_config/archify/bin/archify.mjs +2139 -0
- package/skills/global_config/archify/bin/open-artifact.mjs +86 -0
- package/skills/global_config/archify/bin/preview.mjs +653 -0
- package/skills/global_config/archify/bin/visual-check.mjs +829 -0
- package/skills/global_config/archify/brand-marks/README.md +31 -0
- package/skills/global_config/archify/brand-marks/catalog.json +131 -0
- package/skills/global_config/archify/delta/architecture-delta.mjs +1232 -0
- package/skills/global_config/archify/examples/agent-run.lifecycle.json +60 -0
- package/skills/global_config/archify/examples/agent-tool-call.workflow.json +94 -0
- package/skills/global_config/archify/examples/async-job-roundtrip.sequence.json +61 -0
- package/skills/global_config/archify/examples/brand-aware-delivery.architecture.json +47 -0
- package/skills/global_config/archify/examples/cache-miss-request.sequence.json +82 -0
- package/skills/global_config/archify/examples/checkout-platform.base.architecture.json +31 -0
- package/skills/global_config/archify/examples/checkout-platform.head.architecture.json +31 -0
- package/skills/global_config/archify/examples/deployment-release.lifecycle.json +49 -0
- package/skills/global_config/archify/examples/event-stream.dataflow.json +57 -0
- package/skills/global_config/archify/examples/incident-response.workflow.json +64 -0
- package/skills/global_config/archify/examples/product-analytics.dataflow.json +76 -0
- package/skills/global_config/archify/examples/production-deployment.architecture.json +71 -0
- package/skills/global_config/archify/examples/release-delivery.workflow.json +62 -0
- package/skills/global_config/archify/examples/web-app.architecture.json +46 -0
- package/skills/global_config/archify/migrations/workflow-v2.mjs +279 -0
- package/skills/global_config/archify/package.json +39 -0
- package/skills/global_config/archify/recipes/scenarios.mjs +391 -0
- package/skills/global_config/archify/references/authoring-contract.md +247 -0
- package/skills/global_config/archify/references/brand-marks.md +65 -0
- package/skills/global_config/archify/references/delivery-contract.md +138 -0
- package/skills/global_config/archify/references/viewer-runtime.md +45 -0
- package/skills/global_config/archify/renderers/architecture/grid.mjs +62 -0
- package/skills/global_config/archify/renderers/architecture/render-architecture.mjs +1078 -0
- package/skills/global_config/archify/renderers/dataflow/README.md +104 -0
- package/skills/global_config/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- package/skills/global_config/archify/renderers/lifecycle/README.md +115 -0
- package/skills/global_config/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- package/skills/global_config/archify/renderers/sequence/README.md +114 -0
- package/skills/global_config/archify/renderers/sequence/render-sequence.mjs +464 -0
- package/skills/global_config/archify/renderers/shared/brand-marks.mjs +563 -0
- package/skills/global_config/archify/renderers/shared/cli.mjs +218 -0
- package/skills/global_config/archify/renderers/shared/desktop-readability.mjs +26 -0
- package/skills/global_config/archify/renderers/shared/diagnostics.mjs +160 -0
- package/skills/global_config/archify/renderers/shared/engineering-profiles.mjs +157 -0
- package/skills/global_config/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
- package/skills/global_config/archify/renderers/shared/generated-validators.mjs +13 -0
- package/skills/global_config/archify/renderers/shared/geometry.mjs +1423 -0
- package/skills/global_config/archify/renderers/shared/i18n.mjs +595 -0
- package/skills/global_config/archify/renderers/shared/layout-report.mjs +40 -0
- package/skills/global_config/archify/renderers/shared/legend.mjs +217 -0
- package/skills/global_config/archify/renderers/shared/output-path.mjs +340 -0
- package/skills/global_config/archify/renderers/shared/repository-evidence.mjs +239 -0
- package/skills/global_config/archify/renderers/shared/repository-location.mjs +58 -0
- package/skills/global_config/archify/renderers/shared/text-fit.mjs +49 -0
- package/skills/global_config/archify/renderers/shared/utils.mjs +232 -0
- package/skills/global_config/archify/renderers/shared/validator.mjs +86 -0
- package/skills/global_config/archify/renderers/workflow/README.md +223 -0
- package/skills/global_config/archify/renderers/workflow/render-workflow.mjs +35 -0
- package/skills/global_config/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- package/skills/global_config/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- package/skills/global_config/archify/schemas/README.md +211 -0
- package/skills/global_config/archify/schemas/architecture.schema.json +178 -0
- package/skills/global_config/archify/schemas/common.schema.json +115 -0
- package/skills/global_config/archify/schemas/dataflow.schema.json +243 -0
- package/skills/global_config/archify/schemas/lifecycle.schema.json +266 -0
- package/skills/global_config/archify/schemas/sequence.schema.json +223 -0
- package/skills/global_config/archify/schemas/workflow.schema.json +428 -0
- package/skills/global_config/archify/scripts/check-render-output.mjs +916 -0
- package/skills/global_config/archify/scripts/generate-brand-marks.mjs +141 -0
- package/skills/global_config/archify/scripts/generate-validators.mjs +66 -0
- package/skills/global_config/archify/scripts/render-examples.mjs +26 -0
- package/skills/global_config/archify/skill-release.json +10 -0
- package/skills/global_config/bdb-security-audit/SKILL.md +109 -0
- package/skills/global_config/bdb-security-audit/references/audit-checklists.md +172 -0
- package/skills/global_config/bdb-security-audit/references/skylos-guide.md +139 -0
- package/skills/global_config/bdb-security-audit/references/xalgorix-bridge.md +110 -0
- package/skills/global_config/bdbdesignpro/SKILL.md +4 -4
- package/skills/global_config/bdbdesignpro/references/bdb-motion-tokens.md +52 -31
- package/skills/global_config/bdbresilience/SKILL.md +10 -0
- package/skills/global_config/brag/SKILL.md +179 -0
- package/skills/global_config/brag/assets/music/README.md +20 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.json +3846 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.md +35 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.json +1826 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.md +35 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.json +2266 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.md +35 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.json +2806 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.md +35 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.json +2796 -0
- package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.md +35 -0
- package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-1-by-ende-dot-app.mp3 +0 -0
- package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-10-by-ende-dot-app.mp3 +0 -0
- package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-11-by-ende-dot-app.mp3 +0 -0
- package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-12-by-ende-dot-app.mp3 +0 -0
- package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-9-by-ende-dot-app.mp3 +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-fan-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-fan-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-place-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-place-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-place-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-place-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-shove-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-shove-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-shove-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-shove-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-shuffle.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-5.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-6.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-7.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/card-slide-8.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/cards-pack-open-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/cards-pack-open-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chip-lay-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chip-lay-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chip-lay-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-collide-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-collide-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-collide-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-collide-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-handle-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-handle-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-handle-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-handle-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-handle-6.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-5.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/chips-stack-6.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-grab-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-grab-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-shake-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-shake-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-shake-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-throw-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-throw-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/dice-throw-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/die-throw-1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/die-throw-2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/die-throw-3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/casino/die-throw-4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_grass_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_grass_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_grass_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_grass_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_grass_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_snow_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_snow_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_snow_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_snow_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_snow_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_wood_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_wood_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_wood_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_wood_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/footstep_wood_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_light_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_light_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactMining_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_light_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_light_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_light_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_light_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_light_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_000.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/bong_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/click_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/click_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/click_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/click_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/click_005.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/drop_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/drop_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/drop_003.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/error_005.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/error_006.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/glitch_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/glitch_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/select_008.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_001.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_002.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_004.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_005.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_006.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/interface/switch_007.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-001.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-002.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-003.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-004.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-005.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-006.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-007.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-008.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-009.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-010.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-011.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-012.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-013.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-014.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-015.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-016.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-017.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-018.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-019.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-020.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-021.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-022.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-023.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-024.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-025.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-026.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-027.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-028.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-029.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-030.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-031.wav +0 -0
- package/skills/global_config/brag/assets/sfx/keyboard/keypress-032.wav +0 -0
- package/skills/global_config/brag/assets/sfx/sfx-analysis.json +15584 -0
- package/skills/global_config/brag/assets/sfx/sfx-analysis.md +75 -0
- package/skills/global_config/brag/assets/sfx/ui/click1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/click2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/click3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/click4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/click5.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/mouseclick1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/rollover1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/rollover2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/rollover4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/rollover5.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch1.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch10.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch11.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch12.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch13.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch14.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch15.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch16.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch17.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch18.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch19.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch2.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch20.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch21.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch22.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch23.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch24.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch25.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch26.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch27.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch28.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch29.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch3.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch30.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch31.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch32.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch33.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch34.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch35.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch36.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch37.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch38.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch4.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch5.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch6.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch7.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch8.ogg +0 -0
- package/skills/global_config/brag/assets/sfx/ui/switch9.ogg +0 -0
- package/skills/global_config/brag/references/audio.md +307 -0
- package/skills/global_config/brag/references/step-1-inspect.md +133 -0
- package/skills/global_config/brag/references/step-2-plan.md +234 -0
- package/skills/global_config/brag/references/step-3-compose.md +210 -0
- package/skills/global_config/brag/references/step-4-deliver.md +168 -0
- package/skills/global_config/brag/references/tones.md +231 -0
- package/skills/global_config/brag/scripts/analyze_music_cues.py +309 -0
- package/skills/global_config/brag/scripts/pyproject.toml +14 -0
- package/skills/global_config/brag/scripts/uv.lock +819 -0
- package/skills/global_config/deja-memory/SKILL.md +42 -0
- package/skills/global_config/editable-design/LICENSE +202 -0
- package/skills/global_config/editable-design/README.md +34 -0
- package/skills/global_config/editable-design/SKILL.md +630 -0
- package/skills/global_config/editable-design/THIRD_PARTY_NOTICES.md +10 -0
- package/skills/global_config/editable-design/agents/openai.yaml +4 -0
- package/skills/global_config/editable-design/assets/editor/layer-editor.css +262 -0
- package/skills/global_config/editable-design/assets/editor/layer-editor.js +1929 -0
- package/skills/global_config/editable-design/assets/poster-starter/README.md +92 -0
- package/skills/global_config/editable-design/assets/poster-starter/assets/.gitkeep +0 -0
- package/skills/global_config/editable-design/assets/poster-starter/index.html +91 -0
- package/skills/global_config/editable-design/assets/poster-starter/poster.json +6 -0
- package/skills/global_config/editable-design/assets/poster-starter/reference/.gitkeep +1 -0
- package/skills/global_config/editable-design/assets/replay/icons/assets.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/html.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/input.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/layers.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/plan.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/reference.png +0 -0
- package/skills/global_config/editable-design/assets/replay/icons/review.png +0 -0
- package/skills/global_config/editable-design/assets/replay/index.html +59 -0
- package/skills/global_config/editable-design/assets/replay/replay-motion.js +410 -0
- package/skills/global_config/editable-design/assets/replay/replay.css +380 -0
- package/skills/global_config/editable-design/assets/replay/replay.js +374 -0
- package/skills/global_config/editable-design/font-kit/package-lock.json +115 -0
- package/skills/global_config/editable-design/font-kit/package.json +19 -0
- package/skills/global_config/editable-design/pack.sh +20 -0
- package/skills/global_config/editable-design/references/asset-architecture.md +72 -0
- package/skills/global_config/editable-design/references/editor-pitfalls.md +70 -0
- package/skills/global_config/editable-design/references/editor-runtime.md +131 -0
- package/skills/global_config/editable-design/references/font-system.md +89 -0
- package/skills/global_config/editable-design/references/imagery.md +145 -0
- package/skills/global_config/editable-design/references/layout-typography.md +116 -0
- package/skills/global_config/editable-design/references/replay-contract.md +169 -0
- package/skills/global_config/editable-design/scripts/_browser.mjs +247 -0
- package/skills/global_config/editable-design/scripts/bake.mjs +87 -0
- package/skills/global_config/editable-design/scripts/build-replay.mjs +316 -0
- package/skills/global_config/editable-design/scripts/check-contract.mjs +293 -0
- package/skills/global_config/editable-design/scripts/check-fonts.sh +252 -0
- package/skills/global_config/editable-design/scripts/check-poster.sh +70 -0
- package/skills/global_config/editable-design/scripts/doctor.sh +78 -0
- package/skills/global_config/editable-design/scripts/explode.mjs +115 -0
- package/skills/global_config/editable-design/scripts/font-kit.mjs +187 -0
- package/skills/global_config/editable-design/scripts/import-asset.sh +23 -0
- package/skills/global_config/editable-design/scripts/init-poster.sh +64 -0
- package/skills/global_config/editable-design/scripts/install-font-kit.sh +13 -0
- package/skills/global_config/editable-design/scripts/package-lock.json +334 -0
- package/skills/global_config/editable-design/scripts/package.json +14 -0
- package/skills/global_config/editable-design/scripts/remove-chroma-key.py +201 -0
- package/skills/global_config/editable-design/scripts/render-poster.sh +202 -0
- package/skills/global_config/editable-design/scripts/trace.sh +159 -0
- package/skills/global_config/editable-design/scripts/verify-replay.mjs +97 -0
- package/skills/global_config/editable-design/scripts/verify.mjs +782 -0
- package/skills/global_config/editable-design/scripts/wire-editor.mjs +104 -0
- package/skills/global_config/editable-design/tests/fixtures/small-explode/index.html +86 -0
- package/skills/global_config/plan-canvas/SKILL.md +8 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Verify that every font family the poster asks for actually resolves.
|
|
3
|
+
#
|
|
4
|
+
# A missing family raises no error anywhere: the browser silently falls back to
|
|
5
|
+
# a default face, the render succeeds, the pixel dimensions check out, and the
|
|
6
|
+
# poster ships with the wrong typography. Nothing else in this plugin can catch
|
|
7
|
+
# that, which is why it gets its own command.
|
|
8
|
+
#
|
|
9
|
+
# Detection compares a full metric signature against a sentinel family that
|
|
10
|
+
# cannot exist. Width alone is not enough — many CJK faces share an advance
|
|
11
|
+
# width — so the signature also covers the actual bounding box at two sizes,
|
|
12
|
+
# measured for a Latin sample and a CJK sample separately.
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
html=""
|
|
17
|
+
requested=""
|
|
18
|
+
while [[ $# -gt 0 ]]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--family)
|
|
21
|
+
[[ $# -ge 2 ]] || { echo "--family requires a font family name" >&2; exit 2; }
|
|
22
|
+
requested="${requested}${2}"$'\n'
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
--help|-h)
|
|
26
|
+
echo "usage: check-fonts.sh HTML"
|
|
27
|
+
echo " check-fonts.sh --family FAMILY [--family FAMILY...]"
|
|
28
|
+
exit 0
|
|
29
|
+
;;
|
|
30
|
+
--*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
31
|
+
*)
|
|
32
|
+
[[ -z "$html" ]] || { echo "only one HTML file may be checked" >&2; exit 2; }
|
|
33
|
+
html="$1"
|
|
34
|
+
shift
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
if [[ -z "$requested" ]]; then
|
|
40
|
+
[[ -n "$html" ]] || { echo "usage: check-fonts.sh HTML or --family FAMILY" >&2; exit 2; }
|
|
41
|
+
test -f "$html" || { echo "no such file: $html" >&2; exit 2; }
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
bundled_families=""
|
|
45
|
+
if [[ -n "$html" ]]; then
|
|
46
|
+
bundled_families=$(
|
|
47
|
+
perl -0ne '
|
|
48
|
+
while (/\@font-face\s*\{(.*?)\}/sg) {
|
|
49
|
+
$block = $1;
|
|
50
|
+
if ($block =~ /font-family\s*:\s*(["'"'"']?)([^;"'"'"']+)\1\s*;/s) {
|
|
51
|
+
$family = $2;
|
|
52
|
+
$family =~ s/^\s+|\s+$//g;
|
|
53
|
+
print "$family\n";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
' "$html" | sort -u
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
html_dir="$(cd "$(dirname "$html")" && pwd)"
|
|
60
|
+
missing_assets=0
|
|
61
|
+
while IFS= read -r raw_url; do
|
|
62
|
+
[[ -n "$raw_url" ]] || continue
|
|
63
|
+
font_url="$(printf '%s' "$raw_url" | sed -e 's/^['"'"'"]//' -e 's/['"'"'"]$//' -e 's/[?#].*$//')"
|
|
64
|
+
case "$font_url" in
|
|
65
|
+
data:*|http://*|https://*) continue ;;
|
|
66
|
+
esac
|
|
67
|
+
if [[ ! -f "$html_dir/$font_url" ]]; then
|
|
68
|
+
printf 'FAIL %-28s missing local font asset\n' "$font_url"
|
|
69
|
+
missing_assets=$(( missing_assets + 1 ))
|
|
70
|
+
fi
|
|
71
|
+
done < <(
|
|
72
|
+
perl -0ne 'while (/\@font-face\s*\{(.*?)\}/sg) { $b=$1; while ($b =~ /url\(([^)]+)\)/g) { print "$1\n" } }' "$html"
|
|
73
|
+
)
|
|
74
|
+
[[ "$missing_assets" -eq 0 ]] || exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Collect every named family out of font-family declarations and --font-* custom
|
|
78
|
+
# properties, dropping generic keywords and var() references.
|
|
79
|
+
if [[ -n "$requested" ]]; then
|
|
80
|
+
families="$(printf '%s' "$requested" | sed '/^[[:space:]]*$/d' | sort -u)"
|
|
81
|
+
else
|
|
82
|
+
families=$(
|
|
83
|
+
grep -o -E '(font-family|--font-[a-zA-Z-]+)[[:space:]]*:[^;}]*' "$html" \
|
|
84
|
+
| sed 's/^[^:]*:[[:space:]]*//' \
|
|
85
|
+
| tr ',' '\n' \
|
|
86
|
+
| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \
|
|
87
|
+
-e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'\$//" \
|
|
88
|
+
| grep -v -E '^(serif|sans-serif|monospace|cursive|fantasy|system-ui|math|emoji|fangsong|ui-[a-z-]+|inherit|initial|unset|revert)$' \
|
|
89
|
+
| grep -v -E '^(var\(|$)' \
|
|
90
|
+
| sort -u
|
|
91
|
+
)
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
if [[ -n "$bundled_families" ]]; then
|
|
95
|
+
while IFS= read -r family; do
|
|
96
|
+
[[ -n "$family" ]] || continue
|
|
97
|
+
printf 'ok %-28s bundled @font-face\n' "$family"
|
|
98
|
+
done <<< "$bundled_families"
|
|
99
|
+
families=$(
|
|
100
|
+
comm -23 \
|
|
101
|
+
<(printf '%s\n' "$families" | sed '/^[[:space:]]*$/d' | sort -u) \
|
|
102
|
+
<(printf '%s\n' "$bundled_families" | sed '/^[[:space:]]*$/d' | sort -u)
|
|
103
|
+
)
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
[[ -n "$families" ]] || {
|
|
107
|
+
[[ -n "$bundled_families" ]] && echo "all named families are bundled and their local files exist" || echo "no named font families found in $html"
|
|
108
|
+
exit 0
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
browser="$("$here/render-poster.sh" --probe | awk '{ $1 = ""; sub(/^ +/, ""); print }')"
|
|
112
|
+
[[ -n "$browser" && -x "$browser" ]] || {
|
|
113
|
+
echo "no Chromium-based browser found, font check unavailable. Set EDITABLE_DESIGN_BROWSER=<executable>" >&2
|
|
114
|
+
exit 1
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
families_json=$(
|
|
118
|
+
printf '%s\n' "$families" \
|
|
119
|
+
| sed 's/\\/\\\\/g; s/"/\\"/g' \
|
|
120
|
+
| awk '{ printf "%s\"%s\"", (NR > 1 ? "," : ""), $0 }'
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
probe="$(mktemp -d "${TMPDIR:-/tmp}/poster-font-probe.XXXXXX")"
|
|
124
|
+
profile="$(mktemp -d "${TMPDIR:-/tmp}/poster-font-profile.XXXXXX")"
|
|
125
|
+
probe_pid=""
|
|
126
|
+
|
|
127
|
+
profile_pids() {
|
|
128
|
+
ps -axo pid=,command= \
|
|
129
|
+
| awk -v marker="--user-data-dir=$profile" \
|
|
130
|
+
'index($0, marker) && index($0, "awk -v marker=") == 0 { print $1 }'
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
stop_browser() {
|
|
134
|
+
local pids=""
|
|
135
|
+
local _
|
|
136
|
+
pids="$(profile_pids)"
|
|
137
|
+
[[ -n "$pids" ]] && kill $pids 2>/dev/null || true
|
|
138
|
+
for _ in $(seq 1 10); do
|
|
139
|
+
pids="$(profile_pids)"
|
|
140
|
+
[[ -z "$pids" ]] && break
|
|
141
|
+
sleep 0.1
|
|
142
|
+
done
|
|
143
|
+
pids="$(profile_pids)"
|
|
144
|
+
[[ -n "$pids" ]] && kill -KILL $pids 2>/dev/null || true
|
|
145
|
+
[[ -n "$probe_pid" ]] && wait "$probe_pid" 2>/dev/null || true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
cleanup() {
|
|
149
|
+
stop_browser
|
|
150
|
+
[[ "$probe" == *"/poster-font-probe."* ]] && rm -rf -- "$probe"
|
|
151
|
+
[[ "$profile" == *"/poster-font-profile."* ]] && rm -rf -- "$profile"
|
|
152
|
+
}
|
|
153
|
+
trap cleanup EXIT INT TERM
|
|
154
|
+
|
|
155
|
+
cat >"$probe/probe.html" <<PROBE
|
|
156
|
+
<!doctype html><html><head><meta charset="utf-8"></head><body><script>
|
|
157
|
+
const FAMILIES = [${families_json}];
|
|
158
|
+
// Three generic bases rather than one nonexistent sentinel. A single sentinel
|
|
159
|
+
// cannot see a family that happens to BE the platform default for that script
|
|
160
|
+
// — PingFang SC is macOS's default CJK sans, so stacking it over a sentinel
|
|
161
|
+
// produces byte-identical metrics and reads as missing. Comparing against
|
|
162
|
+
// serif, sans-serif and monospace fixes that: a real family overrides at least
|
|
163
|
+
// one of them.
|
|
164
|
+
const BASES = ['serif', 'sans-serif', 'monospace'];
|
|
165
|
+
const SAMPLES = { latin: 'AWmgQ019jil', cjk: '晨雾高山茶永' };
|
|
166
|
+
|
|
167
|
+
function signature(text, stack) {
|
|
168
|
+
const ctx = document.createElement('canvas').getContext('2d');
|
|
169
|
+
const parts = [];
|
|
170
|
+
for (const size of [48, 73]) {
|
|
171
|
+
ctx.font = size + 'px ' + stack;
|
|
172
|
+
const m = ctx.measureText(text);
|
|
173
|
+
parts.push(
|
|
174
|
+
m.width.toFixed(3),
|
|
175
|
+
(m.actualBoundingBoxAscent || 0).toFixed(3),
|
|
176
|
+
(m.actualBoundingBoxDescent || 0).toFixed(3),
|
|
177
|
+
(m.actualBoundingBoxLeft || 0).toFixed(3),
|
|
178
|
+
(m.actualBoundingBoxRight || 0).toFixed(3)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return parts.join('|');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const lines = FAMILIES.map((family) => {
|
|
185
|
+
const quoted = JSON.stringify(family);
|
|
186
|
+
const covers = {};
|
|
187
|
+
for (const [name, text] of Object.entries(SAMPLES)) {
|
|
188
|
+
covers[name] = BASES.some(
|
|
189
|
+
(base) => signature(text, quoted + ', ' + base) !== signature(text, base)
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
const verdict = covers.latin || covers.cjk
|
|
193
|
+
? (covers.cjk ? 'ok\tcjk + latin' : 'ok\tlatin only')
|
|
194
|
+
: 'MISSING\t-';
|
|
195
|
+
return 'FONTPROBE\t' + family + '\t' + verdict;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Leading newline matters: --dump-dom emits "<body>" immediately before the
|
|
199
|
+
// first line, so without it the first family never matches a line-anchored grep.
|
|
200
|
+
document.body.textContent = '\n' + lines.join('\n') + '\n';
|
|
201
|
+
</script></body></html>
|
|
202
|
+
PROBE
|
|
203
|
+
|
|
204
|
+
"$browser" \
|
|
205
|
+
--headless --disable-gpu --no-first-run --no-default-browser-check \
|
|
206
|
+
--disable-extensions --disable-background-networking --disable-sync \
|
|
207
|
+
--disable-default-apps --mute-audio \
|
|
208
|
+
--user-data-dir="$profile" \
|
|
209
|
+
--dump-dom "file://$probe/probe.html" \
|
|
210
|
+
>"$probe/dom.html" 2>/dev/null &
|
|
211
|
+
probe_pid=$!
|
|
212
|
+
|
|
213
|
+
# --dump-dom writes to stdout and Chrome buffers it until exit, so polling the
|
|
214
|
+
# file for content never succeeds early. Wait for the process itself instead.
|
|
215
|
+
for _ in $(seq 1 20); do
|
|
216
|
+
kill -0 "$probe_pid" 2>/dev/null || break
|
|
217
|
+
sleep 0.25
|
|
218
|
+
done
|
|
219
|
+
if kill -0 "$probe_pid" 2>/dev/null; then
|
|
220
|
+
stop_browser
|
|
221
|
+
else
|
|
222
|
+
wait "$probe_pid" 2>/dev/null || true
|
|
223
|
+
fi
|
|
224
|
+
probe_pid=""
|
|
225
|
+
|
|
226
|
+
grep -q 'FONTPROBE' "$probe/dom.html" 2>/dev/null || {
|
|
227
|
+
echo "the font probe returned nothing - the browser probably failed to start" >&2
|
|
228
|
+
exit 3
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
missing=0
|
|
232
|
+
while IFS=$'\t' read -r _ family verdict coverage; do
|
|
233
|
+
[[ -n "$family" ]] || continue
|
|
234
|
+
if [[ "$verdict" == "MISSING" ]]; then
|
|
235
|
+
printf 'FAIL %-28s not installed - the browser will silently fall back\n' "$family"
|
|
236
|
+
missing=$(( missing + 1 ))
|
|
237
|
+
else
|
|
238
|
+
printf 'ok %-28s %s\n' "$family" "$coverage"
|
|
239
|
+
fi
|
|
240
|
+
done < <(grep '^FONTPROBE' "$probe/dom.html" | sed 's/&/\&/g; s/</</g; s/>/>/g; s/"/"/g')
|
|
241
|
+
|
|
242
|
+
if [[ "$missing" -gt 0 ]]; then
|
|
243
|
+
echo
|
|
244
|
+
echo "Replace these $missing families, or use ones confirmed present. A missing font" >&2
|
|
245
|
+
echo "raises no error: the render succeeds, the dimensions check out, and only the" >&2
|
|
246
|
+
echo "type on the finished poster looks subtly wrong." >&2
|
|
247
|
+
exit 1
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
echo
|
|
251
|
+
echo "Families marked \"latin only\" must not set CJK text: every character would come"
|
|
252
|
+
echo "from a fallback face."
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Fast, self-contained checks for the poster contract. Visual quality still
|
|
3
|
+
# requires reading the rendered PNG; this catches deterministic packaging and
|
|
4
|
+
# markup failures before Chrome starts.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
html="${1:?usage: check-poster.sh HTML}"
|
|
8
|
+
test -f "$html" || { echo "no such file: $html" >&2; exit 2; }
|
|
9
|
+
|
|
10
|
+
project="$(cd "$(dirname "$html")" && pwd)"
|
|
11
|
+
html="$project/$(basename "$html")"
|
|
12
|
+
config="$project/poster.json"
|
|
13
|
+
failures=0
|
|
14
|
+
|
|
15
|
+
fail() {
|
|
16
|
+
echo "FAIL $*" >&2
|
|
17
|
+
failures=$(( failures + 1 ))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
read_num() {
|
|
21
|
+
sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p" "$2" | head -1
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test -f "$config" || fail "missing poster.json"
|
|
25
|
+
|
|
26
|
+
if [[ -f "$config" ]]; then
|
|
27
|
+
width="$(read_num width "$config")"
|
|
28
|
+
height="$(read_num height "$config")"
|
|
29
|
+
[[ -n "$width" && -n "$height" ]] || fail "cannot read canvas width and height from poster.json"
|
|
30
|
+
if [[ -n "$width" && -n "$height" ]]; then
|
|
31
|
+
grep -q "data-canvas-width=\"$width\"" "$html" || fail "HTML canvas width does not match poster.json ($width)"
|
|
32
|
+
grep -q "data-canvas-height=\"$height\"" "$html" || fail "HTML canvas height does not match poster.json ($height)"
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
grep -q 'position:[[:space:]]*relative' "$html" || fail "canvas must be position: relative"
|
|
37
|
+
grep -q 'overflow:[[:space:]]*hidden' "$html" || fail "canvas must hide overflow"
|
|
38
|
+
|
|
39
|
+
if grep -Eq 'poster-preview|Your poster is taking shape|The first version will appear here automatically' "$html" 2>/dev/null; then
|
|
40
|
+
fail "starter placeholder content remains"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
grep -Eiq '<script([[:space:]>])' "$html" && fail "scripts are not allowed in the shipping poster"
|
|
44
|
+
grep -Eiq '@media([[:space:](])' "$html" && fail "media queries are not allowed on a fixed canvas"
|
|
45
|
+
grep -Eiq '[0-9.]([[:space:]]*)(vw|vh|vmin|vmax)([^a-zA-Z]|$)' "$html" && fail "viewport units are not allowed for poster layout"
|
|
46
|
+
grep -Eiq "(src|href)[[:space:]]*=[[:space:]]*['\"](https?:)?//" "$html" && fail "external asset requests are not allowed"
|
|
47
|
+
grep -Eiq "src[[:space:]]*=[[:space:]]*['\"]data:" "$html" && fail "embed generated assets as project files, not data URLs"
|
|
48
|
+
|
|
49
|
+
tmp="$(mktemp -d "${TMPDIR:-/tmp}/poster-contract.XXXXXX")"
|
|
50
|
+
trap 'rm -rf -- "$tmp"' EXIT INT TERM
|
|
51
|
+
|
|
52
|
+
grep -o 'data-layer-id="[^"]*"' "$html" | sed 's/.*="//; s/"$//' | sort >"$tmp/layers" || true
|
|
53
|
+
duplicates="$(uniq -d "$tmp/layers")"
|
|
54
|
+
[[ -z "$duplicates" ]] || fail "duplicate data-layer-id values: $(printf '%s' "$duplicates" | tr '\n' ' ')"
|
|
55
|
+
|
|
56
|
+
grep -o 'src="[^"]*"' "$html" | sed 's/^src="//; s/"$//' >"$tmp/assets" || true
|
|
57
|
+
while IFS= read -r asset; do
|
|
58
|
+
[[ -n "$asset" ]] || continue
|
|
59
|
+
case "$asset" in
|
|
60
|
+
/*|*://*|data:*) fail "asset path must be project-relative: $asset" ;;
|
|
61
|
+
*) [[ -f "$project/$asset" ]] || fail "missing referenced asset: $asset" ;;
|
|
62
|
+
esac
|
|
63
|
+
done <"$tmp/assets"
|
|
64
|
+
|
|
65
|
+
if [[ "$failures" -gt 0 ]]; then
|
|
66
|
+
echo "$failures poster contract check(s) failed" >&2
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
echo "ok poster contract and local assets"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
failures=0
|
|
6
|
+
|
|
7
|
+
ok() { printf '%-22s %s\n' "$1" "OK $2"; }
|
|
8
|
+
warn() { printf '%-22s %s\n' "$1" "OPTIONAL $2"; }
|
|
9
|
+
bad() { printf '%-22s %s\n' "$1" "MISSING $2"; failures=$((failures + 1)); }
|
|
10
|
+
|
|
11
|
+
printf '%s\n\n' "Editable Design doctor"
|
|
12
|
+
|
|
13
|
+
if command -v node >/dev/null 2>&1; then
|
|
14
|
+
node_version="$(node -p 'process.versions.node')"
|
|
15
|
+
node_major="${node_version%%.*}"
|
|
16
|
+
node_minor="$(printf '%s' "$node_version" | cut -d. -f2)"
|
|
17
|
+
if [[ "$node_major" -gt 22 || ( "$node_major" -eq 22 && "$node_minor" -ge 12 ) ]]; then ok "Node.js" "$node_version"; else bad "Node.js" "$node_version; requires >=22.12"; fi
|
|
18
|
+
else
|
|
19
|
+
bad "Node.js" "requires >=22.12"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if command -v npm >/dev/null 2>&1; then ok "npm" "$(npm --version)"; else bad "npm" "required for npm ci --prefix scripts"; fi
|
|
23
|
+
|
|
24
|
+
if [[ -f "$here/node_modules/puppeteer-core/package.json" ]]; then
|
|
25
|
+
version="$(node -p "require('$here/node_modules/puppeteer-core/package.json').version" 2>/dev/null || true)"
|
|
26
|
+
ok "puppeteer-core" "${version:-installed}"
|
|
27
|
+
else
|
|
28
|
+
bad "puppeteer-core" "run npm ci --prefix scripts"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
font_kit="$here/../font-kit/node_modules"
|
|
32
|
+
if [[ -f "$font_kit/@fontsource-variable/fraunces/package.json" && -f "$font_kit/@fontsource-variable/noto-sans-sc/package.json" ]]; then
|
|
33
|
+
font_count="$(find "$font_kit" -mindepth 3 -maxdepth 3 -name package.json | wc -l | tr -d ' ')"
|
|
34
|
+
ok "Font kit" "$font_count curated packages"
|
|
35
|
+
else
|
|
36
|
+
bad "Font kit" "run scripts/install-font-kit.sh"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
browser=""
|
|
40
|
+
for candidate in "${EDITABLE_DESIGN_BROWSER:-}" "${PUPPETEER_EXECUTABLE_PATH:-}" "${POSTER_BROWSER:-}" "${CHROME_PATH:-}"; do
|
|
41
|
+
if [[ -n "$candidate" && -x "$candidate" ]]; then browser="$candidate"; break; fi
|
|
42
|
+
done
|
|
43
|
+
if [[ -z "$browser" ]]; then
|
|
44
|
+
for candidate in chromium google-chrome chrome; do
|
|
45
|
+
browser="$(command -v "$candidate" 2>/dev/null || true)"
|
|
46
|
+
[[ -n "$browser" ]] && break
|
|
47
|
+
done
|
|
48
|
+
fi
|
|
49
|
+
if [[ -z "$browser" ]]; then
|
|
50
|
+
for candidate in \
|
|
51
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
|
|
52
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium" \
|
|
53
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" \
|
|
54
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" \
|
|
55
|
+
"/usr/bin/google-chrome" "/usr/bin/chromium" "/usr/bin/chromium-browser"; do
|
|
56
|
+
if [[ -x "$candidate" ]]; then browser="$candidate"; break; fi
|
|
57
|
+
done
|
|
58
|
+
fi
|
|
59
|
+
if [[ -n "$browser" ]]; then ok "Chromium browser" "$browser"; else bad "Chromium browser" "set EDITABLE_DESIGN_BROWSER"; fi
|
|
60
|
+
|
|
61
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
62
|
+
python_version="$(python3 -c 'import sys; print(".".join(map(str, sys.version_info[:3])))')"
|
|
63
|
+
warn "Python" "$python_version; optional cutout processing only"
|
|
64
|
+
if python3 -c 'import PIL' >/dev/null 2>&1; then warn "Pillow" "installed"; else warn "Pillow" "needed only for cutout processing"; fi
|
|
65
|
+
else
|
|
66
|
+
warn "Python" "needed only for cutout processing"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
warn "Image generation" "host-dependent; auto mode can fall back to off"
|
|
70
|
+
if [[ "${EDITABLE_DESIGN_NO_SANDBOX:-0}" == "1" ]]; then warn "Browser sandbox" "disabled by explicit environment setting"; else ok "Browser sandbox" "enabled"; fi
|
|
71
|
+
|
|
72
|
+
printf '\n'
|
|
73
|
+
if [[ "$failures" -eq 0 ]]; then
|
|
74
|
+
printf '%s\n' "Core workflow ready."
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
printf '%s\n' "Core workflow has $failures missing requirement(s)."
|
|
78
|
+
exit 1
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* explode.mjs —— 把已标注图层的海报生成横向拆解展示稿
|
|
4
|
+
*
|
|
5
|
+
* node explode.mjs <海报 index.html> [输出 HTML]
|
|
6
|
+
*
|
|
7
|
+
* 默认产出同目录 layers.html。完整成稿总览、未标记背景和一级内容模块
|
|
8
|
+
* 从原稿位置动态散开成组件画廊。每个内容叶子仍是独立 DOM,不把整稿压成图片。
|
|
9
|
+
*/
|
|
10
|
+
import { writeFileSync, existsSync } from 'node:fs';
|
|
11
|
+
import { dirname, join, resolve } from 'node:path';
|
|
12
|
+
import { launch, open, wireTemp } from './_browser.mjs';
|
|
13
|
+
|
|
14
|
+
const file = process.argv[2];
|
|
15
|
+
if (!file || !existsSync(resolve(file))) {
|
|
16
|
+
console.error('用法: node explode.mjs <海报 index.html> [输出 HTML]');
|
|
17
|
+
process.exit(2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const src = resolve(file);
|
|
21
|
+
const out = process.argv[3] ? resolve(process.argv[3]) : join(dirname(src), 'layers.html');
|
|
22
|
+
if (out === src) {
|
|
23
|
+
console.error('❌ 输出路径不能覆盖源 HTML');
|
|
24
|
+
process.exit(2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const wired = wireTemp(src, '_hf_explode.html');
|
|
28
|
+
const browser = await launch();
|
|
29
|
+
let code = 0;
|
|
30
|
+
try {
|
|
31
|
+
const { page, errors } = await open(browser, wired.file, { waitEditor: true });
|
|
32
|
+
const expected = await page.evaluate(() => {
|
|
33
|
+
const layers = window.__layerEditor.layers();
|
|
34
|
+
const groups = [...window.__layerEditor.state.groups.values()];
|
|
35
|
+
const grouped = new Set(groups.flatMap((group) => group.memberIds));
|
|
36
|
+
const primary = groups.length + layers.filter((layer) => !grouped.has(layer.id)).length;
|
|
37
|
+
const textSupplements = primary < 5 ? layers.filter(({ id, el }) => {
|
|
38
|
+
if (!grouped.has(id)) return false;
|
|
39
|
+
const role = (el.dataset.explodeRole || 'copy').trim();
|
|
40
|
+
if (['surface', 'image', 'icon', 'decoration'].includes(role)) return false;
|
|
41
|
+
return Boolean((el.innerText || el.textContent || '').replace(/\s+/g, ' ').trim());
|
|
42
|
+
}).length : 0;
|
|
43
|
+
return { layers: layers.length, groups: groups.length, primary, textSupplements, units: primary + textSupplements + 2 };
|
|
44
|
+
});
|
|
45
|
+
const html = await page.evaluate(() => window.__layerEditor.explodedHTML());
|
|
46
|
+
writeFileSync(out, html);
|
|
47
|
+
|
|
48
|
+
const { page: result, errors: resultErrors } = await open(browser, out, { width: 1600, height: 1000 });
|
|
49
|
+
await result.waitForSelector('html[data-hf-exploded-ready]', { timeout: 20000 });
|
|
50
|
+
const audit = await result.evaluate(() => ({
|
|
51
|
+
board: !!document.querySelector('.hf-exploded-board'),
|
|
52
|
+
units: document.querySelectorAll('.hf-exploded-item').length,
|
|
53
|
+
layers: document.querySelectorAll('[data-exploded-layer]').length,
|
|
54
|
+
uniqueLayers: new Set([...document.querySelectorAll('[data-exploded-layer]')]
|
|
55
|
+
.map((node) => node.dataset.explodedLayer)).size,
|
|
56
|
+
primary: Number(document.querySelector('.hf-exploded-board')?.dataset.explodedPrimaryCount || 0),
|
|
57
|
+
textSupplements: document.querySelectorAll('.hf-exploded-item[data-exploded-text-supplement]').length,
|
|
58
|
+
bases: document.querySelectorAll('.hf-exploded-base').length,
|
|
59
|
+
overviews: document.querySelectorAll('[data-exploded-overview]').length,
|
|
60
|
+
backgrounds: document.querySelectorAll('[data-exploded-background]').length,
|
|
61
|
+
groups: document.querySelectorAll('.hf-exploded-item[data-exploded-group]').length,
|
|
62
|
+
level: document.querySelector('.hf-exploded-board')?.dataset.explodedLevel,
|
|
63
|
+
drilldownUI: !!document.querySelector('.hf-exploded-nav'),
|
|
64
|
+
theme: document.querySelector('.hf-exploded-board')?.dataset.explodedTheme,
|
|
65
|
+
replay: !!document.querySelector('.hf-exploded-replay'),
|
|
66
|
+
motion: document.documentElement.dataset.hfMotion,
|
|
67
|
+
editorUI: !!document.querySelector('.hf-bar,.hf-panel'),
|
|
68
|
+
centerOccupied: (() => {
|
|
69
|
+
const board = document.querySelector('.hf-exploded-board');
|
|
70
|
+
const width = parseFloat(board?.style.width) || 1;
|
|
71
|
+
return [...document.querySelectorAll('.hf-exploded-item')].some((item) => {
|
|
72
|
+
const left = parseFloat(item.style.left) || 0;
|
|
73
|
+
const itemWidth = parseFloat(item.style.width) || 0;
|
|
74
|
+
return left < width * .58 && left + itemWidth > width * .42;
|
|
75
|
+
});
|
|
76
|
+
})(),
|
|
77
|
+
overflow: document.documentElement.scrollWidth > innerWidth + 1
|
|
78
|
+
|| document.documentElement.scrollHeight > innerHeight + 1,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
console.log(`\n拆解展示 · ${src}\n`);
|
|
82
|
+
console.log(` ${audit.board ? '✅' : '❌'} 横向拆解画布`);
|
|
83
|
+
console.log(` ${audit.uniqueLayers === expected.layers ? '✅' : '❌'} 内容叶子 ${audit.uniqueLayers}/${expected.layers}(${audit.layers} 次呈现)`);
|
|
84
|
+
console.log(` ${audit.units === expected.units ? '✅' : '❌'} 组件总数 ${audit.units}/${expected.units}`);
|
|
85
|
+
console.log(` ${audit.primary === expected.primary && audit.textSupplements === expected.textSupplements ? '✅' : '❌'} 少组件文字补充 一级 ${audit.primary},文字 ${audit.textSupplements}`);
|
|
86
|
+
console.log(` ${audit.bases === 0 && audit.centerOccupied ? '✅' : '❌'} 无中央大基底`);
|
|
87
|
+
console.log(` ${audit.overviews === 1 && audit.backgrounds === 1 ? '✅' : '❌'} 总览与背景组件 ${audit.overviews}/${audit.backgrounds}`);
|
|
88
|
+
console.log(` ${audit.groups === expected.groups ? '✅' : '❌'} 一级模块 ${audit.groups}/${expected.groups}`);
|
|
89
|
+
console.log(` ${audit.level === '1' && !audit.drilldownUI ? '✅' : '❌'} 仅一级内容拆解`);
|
|
90
|
+
console.log(` ${['light', 'dark'].includes(audit.theme) ? '✅' : '❌'} 明暗主题 ${audit.theme || '未识别'}`);
|
|
91
|
+
console.log(` ${audit.replay && ['played', 'reduced'].includes(audit.motion) ? '✅' : '❌'} 自动播放与重播 ${audit.motion || '未播放'}`);
|
|
92
|
+
console.log(` ${!audit.editorUI ? '✅' : '❌'} 不含编辑器界面`);
|
|
93
|
+
console.log(` ${!audit.overflow ? '✅' : '❌'} 自适应窗口无滚动溢出`);
|
|
94
|
+
const allErrors = [...errors, ...resultErrors];
|
|
95
|
+
if (allErrors.length) console.log(` ❌ 页面报错 ${allErrors.join('; ')}`);
|
|
96
|
+
|
|
97
|
+
if (!audit.board || audit.uniqueLayers !== expected.layers || audit.units !== expected.units
|
|
98
|
+
|| audit.primary !== expected.primary || audit.textSupplements !== expected.textSupplements
|
|
99
|
+
|| audit.bases !== 0 || !audit.centerOccupied || audit.overviews !== 1 || audit.backgrounds !== 1
|
|
100
|
+
|| audit.groups !== expected.groups
|
|
101
|
+
|| audit.level !== '1' || audit.drilldownUI
|
|
102
|
+
|| !['light', 'dark'].includes(audit.theme) || !audit.replay
|
|
103
|
+
|| !['played', 'reduced'].includes(audit.motion)
|
|
104
|
+
|| audit.editorUI || audit.overflow || allErrors.length) {
|
|
105
|
+
code = 1;
|
|
106
|
+
console.log('\n❌ 拆解稿未通过验收。');
|
|
107
|
+
} else {
|
|
108
|
+
console.log(`\n✅ 已写入 ${out}\n`);
|
|
109
|
+
}
|
|
110
|
+
} finally {
|
|
111
|
+
wired.cleanup();
|
|
112
|
+
await browser.close();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
process.exit(code);
|