@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.
Files changed (486) hide show
  1. package/.agents/agents.md +1 -0
  2. package/.agents/nodes.json +5 -1
  3. package/.agents/state.schema.json +2 -1
  4. package/.agents/vendor-manifest.json +50 -0
  5. package/.claude/agents/architect.md +4 -0
  6. package/.claude/agents/security-reviewer.md +1 -1
  7. package/.claude/hooks/memb-inject.mjs +257 -135
  8. package/.claude/hooks/trail-relay.mjs +18 -0
  9. package/.claude/settings.json +70 -0
  10. package/.claude/workflows/startcycle-dispatch.mjs +29 -1
  11. package/.opencode/agents/architect.md +4 -0
  12. package/.opencode/plugins/bdb-aos.js +75 -0
  13. package/THIRD_PARTY_NOTICES.md +48 -0
  14. package/bin/aos-config.mjs +3 -1
  15. package/bin/aos-uninstall.mjs +55 -1
  16. package/docs/handover/agenttrail-for-ao.md +58 -0
  17. package/docs/handover/deja-for-ao.md +51 -0
  18. package/installer.js +257 -56
  19. package/mcp_config.json +4 -0
  20. package/mcps/mcsc/README.md +24 -0
  21. package/mcps/mcsc/package-lock.json +1234 -0
  22. package/mcps/mcsc/package.json +14 -0
  23. package/mcps/mcsc/packages/core/bin/mcsc.js +162 -0
  24. package/mcps/mcsc/packages/core/rulebook.default.yaml +49 -0
  25. package/mcps/mcsc/packages/core/schema/rulebook.schema.json +56 -0
  26. package/mcps/mcsc/packages/core/src/adapters/agy.js +107 -0
  27. package/mcps/mcsc/packages/core/src/adapters/codex.js +56 -0
  28. package/mcps/mcsc/packages/core/src/adapters/native.js +14 -0
  29. package/mcps/mcsc/packages/core/src/adapters/opencode.js +183 -0
  30. package/mcps/mcsc/packages/core/src/adapters/types.js +21 -0
  31. package/mcps/mcsc/packages/core/src/capabilities/buildOfferTable.js +34 -0
  32. package/mcps/mcsc/packages/core/src/capabilities/registry.js +99 -0
  33. package/mcps/mcsc/packages/core/src/capabilities/types.js +24 -0
  34. package/mcps/mcsc/packages/core/src/detect/cache.js +47 -0
  35. package/mcps/mcsc/packages/core/src/detect/inventory.js +73 -0
  36. package/mcps/mcsc/packages/core/src/detect/probes.js +158 -0
  37. package/mcps/mcsc/packages/core/src/detect/types.js +26 -0
  38. package/mcps/mcsc/packages/core/src/rulebook/load.js +53 -0
  39. package/mcps/mcsc/packages/core/src/rulebook/resolve.js +227 -0
  40. package/mcps/mcsc/packages/core/src/rulebook/rulebook.types.js +89 -0
  41. package/mcps/mcsc/packages/core/src/trail.js +17 -0
  42. package/mcps/mcsc/packages/mcp/server.js +302 -0
  43. package/mcps/mcsc/server.js +2 -0
  44. package/package.json +3 -1
  45. package/skills/basic/bdbmediastorm/SKILL.md +1 -1
  46. package/skills/basic/godmode-ui-ux/SKILL.md +2 -2
  47. package/skills/basic/godmode-ui-ux/references/anti-slop-rules.md +44 -40
  48. package/skills/basic/godmode-ui-ux/references/taste-archetypes.md +49 -0
  49. package/skills/basic/startcycle/SKILL.md +7 -0
  50. package/skills/basic/startcycle-graph/SKILL.md +12 -0
  51. package/skills/basic/startcycle-graph-user/SKILL.md +3 -0
  52. package/skills/basic/teamwork-preview/SKILL.md +2 -0
  53. package/skills/bdbrainstorm/SKILL.md +1 -0
  54. package/skills/global_config/agenttrail/LICENSE +21 -0
  55. package/skills/global_config/agenttrail/SKILL.md +48 -0
  56. package/skills/global_config/agenttrail/bin/agenttrail.mjs +1002 -0
  57. package/skills/global_config/agenttrail/public/index.html +661 -0
  58. package/skills/global_config/aos-project-init/SKILL.md +25 -5
  59. package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +11 -0
  60. package/skills/global_config/aos-setup/SKILL.md +34 -1
  61. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +115 -1
  62. package/skills/global_config/archify/LICENSE +22 -0
  63. package/skills/global_config/archify/SKILL.md +140 -0
  64. package/skills/global_config/archify/THIRD_PARTY_NOTICES.md +69 -0
  65. package/skills/global_config/archify/assets/JetBrainsMono-OFL.txt +93 -0
  66. package/skills/global_config/archify/assets/template.html +14937 -0
  67. package/skills/global_config/archify/bin/archify.mjs +2139 -0
  68. package/skills/global_config/archify/bin/open-artifact.mjs +86 -0
  69. package/skills/global_config/archify/bin/preview.mjs +653 -0
  70. package/skills/global_config/archify/bin/visual-check.mjs +829 -0
  71. package/skills/global_config/archify/brand-marks/README.md +31 -0
  72. package/skills/global_config/archify/brand-marks/catalog.json +131 -0
  73. package/skills/global_config/archify/delta/architecture-delta.mjs +1232 -0
  74. package/skills/global_config/archify/examples/agent-run.lifecycle.json +60 -0
  75. package/skills/global_config/archify/examples/agent-tool-call.workflow.json +94 -0
  76. package/skills/global_config/archify/examples/async-job-roundtrip.sequence.json +61 -0
  77. package/skills/global_config/archify/examples/brand-aware-delivery.architecture.json +47 -0
  78. package/skills/global_config/archify/examples/cache-miss-request.sequence.json +82 -0
  79. package/skills/global_config/archify/examples/checkout-platform.base.architecture.json +31 -0
  80. package/skills/global_config/archify/examples/checkout-platform.head.architecture.json +31 -0
  81. package/skills/global_config/archify/examples/deployment-release.lifecycle.json +49 -0
  82. package/skills/global_config/archify/examples/event-stream.dataflow.json +57 -0
  83. package/skills/global_config/archify/examples/incident-response.workflow.json +64 -0
  84. package/skills/global_config/archify/examples/product-analytics.dataflow.json +76 -0
  85. package/skills/global_config/archify/examples/production-deployment.architecture.json +71 -0
  86. package/skills/global_config/archify/examples/release-delivery.workflow.json +62 -0
  87. package/skills/global_config/archify/examples/web-app.architecture.json +46 -0
  88. package/skills/global_config/archify/migrations/workflow-v2.mjs +279 -0
  89. package/skills/global_config/archify/package.json +39 -0
  90. package/skills/global_config/archify/recipes/scenarios.mjs +391 -0
  91. package/skills/global_config/archify/references/authoring-contract.md +247 -0
  92. package/skills/global_config/archify/references/brand-marks.md +65 -0
  93. package/skills/global_config/archify/references/delivery-contract.md +138 -0
  94. package/skills/global_config/archify/references/viewer-runtime.md +45 -0
  95. package/skills/global_config/archify/renderers/architecture/grid.mjs +62 -0
  96. package/skills/global_config/archify/renderers/architecture/render-architecture.mjs +1078 -0
  97. package/skills/global_config/archify/renderers/dataflow/README.md +104 -0
  98. package/skills/global_config/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  99. package/skills/global_config/archify/renderers/lifecycle/README.md +115 -0
  100. package/skills/global_config/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  101. package/skills/global_config/archify/renderers/sequence/README.md +114 -0
  102. package/skills/global_config/archify/renderers/sequence/render-sequence.mjs +464 -0
  103. package/skills/global_config/archify/renderers/shared/brand-marks.mjs +563 -0
  104. package/skills/global_config/archify/renderers/shared/cli.mjs +218 -0
  105. package/skills/global_config/archify/renderers/shared/desktop-readability.mjs +26 -0
  106. package/skills/global_config/archify/renderers/shared/diagnostics.mjs +160 -0
  107. package/skills/global_config/archify/renderers/shared/engineering-profiles.mjs +157 -0
  108. package/skills/global_config/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  109. package/skills/global_config/archify/renderers/shared/generated-validators.mjs +13 -0
  110. package/skills/global_config/archify/renderers/shared/geometry.mjs +1423 -0
  111. package/skills/global_config/archify/renderers/shared/i18n.mjs +595 -0
  112. package/skills/global_config/archify/renderers/shared/layout-report.mjs +40 -0
  113. package/skills/global_config/archify/renderers/shared/legend.mjs +217 -0
  114. package/skills/global_config/archify/renderers/shared/output-path.mjs +340 -0
  115. package/skills/global_config/archify/renderers/shared/repository-evidence.mjs +239 -0
  116. package/skills/global_config/archify/renderers/shared/repository-location.mjs +58 -0
  117. package/skills/global_config/archify/renderers/shared/text-fit.mjs +49 -0
  118. package/skills/global_config/archify/renderers/shared/utils.mjs +232 -0
  119. package/skills/global_config/archify/renderers/shared/validator.mjs +86 -0
  120. package/skills/global_config/archify/renderers/workflow/README.md +223 -0
  121. package/skills/global_config/archify/renderers/workflow/render-workflow.mjs +35 -0
  122. package/skills/global_config/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  123. package/skills/global_config/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  124. package/skills/global_config/archify/schemas/README.md +211 -0
  125. package/skills/global_config/archify/schemas/architecture.schema.json +178 -0
  126. package/skills/global_config/archify/schemas/common.schema.json +115 -0
  127. package/skills/global_config/archify/schemas/dataflow.schema.json +243 -0
  128. package/skills/global_config/archify/schemas/lifecycle.schema.json +266 -0
  129. package/skills/global_config/archify/schemas/sequence.schema.json +223 -0
  130. package/skills/global_config/archify/schemas/workflow.schema.json +428 -0
  131. package/skills/global_config/archify/scripts/check-render-output.mjs +916 -0
  132. package/skills/global_config/archify/scripts/generate-brand-marks.mjs +141 -0
  133. package/skills/global_config/archify/scripts/generate-validators.mjs +66 -0
  134. package/skills/global_config/archify/scripts/render-examples.mjs +26 -0
  135. package/skills/global_config/archify/skill-release.json +10 -0
  136. package/skills/global_config/bdb-security-audit/SKILL.md +109 -0
  137. package/skills/global_config/bdb-security-audit/references/audit-checklists.md +172 -0
  138. package/skills/global_config/bdb-security-audit/references/skylos-guide.md +139 -0
  139. package/skills/global_config/bdb-security-audit/references/xalgorix-bridge.md +110 -0
  140. package/skills/global_config/bdbdesignpro/SKILL.md +4 -4
  141. package/skills/global_config/bdbdesignpro/references/bdb-motion-tokens.md +52 -31
  142. package/skills/global_config/bdbresilience/SKILL.md +10 -0
  143. package/skills/global_config/brag/SKILL.md +179 -0
  144. package/skills/global_config/brag/assets/music/README.md +20 -0
  145. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.json +3846 -0
  146. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-1-by-ende-dot-app.music-cues.md +35 -0
  147. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.json +1826 -0
  148. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-10-by-ende-dot-app.music-cues.md +35 -0
  149. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.json +2266 -0
  150. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-11-by-ende-dot-app.music-cues.md +35 -0
  151. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.json +2806 -0
  152. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-12-by-ende-dot-app.music-cues.md +35 -0
  153. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.json +2796 -0
  154. package/skills/global_config/brag/assets/music/cues/happy-beats-business-moves-vol-9-by-ende-dot-app.music-cues.md +35 -0
  155. package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-1-by-ende-dot-app.mp3 +0 -0
  156. package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-10-by-ende-dot-app.mp3 +0 -0
  157. package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-11-by-ende-dot-app.mp3 +0 -0
  158. package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-12-by-ende-dot-app.mp3 +0 -0
  159. package/skills/global_config/brag/assets/music/happy-beats-business-moves-vol-9-by-ende-dot-app.mp3 +0 -0
  160. package/skills/global_config/brag/assets/sfx/casino/card-fan-1.ogg +0 -0
  161. package/skills/global_config/brag/assets/sfx/casino/card-fan-2.ogg +0 -0
  162. package/skills/global_config/brag/assets/sfx/casino/card-place-1.ogg +0 -0
  163. package/skills/global_config/brag/assets/sfx/casino/card-place-2.ogg +0 -0
  164. package/skills/global_config/brag/assets/sfx/casino/card-place-3.ogg +0 -0
  165. package/skills/global_config/brag/assets/sfx/casino/card-place-4.ogg +0 -0
  166. package/skills/global_config/brag/assets/sfx/casino/card-shove-1.ogg +0 -0
  167. package/skills/global_config/brag/assets/sfx/casino/card-shove-2.ogg +0 -0
  168. package/skills/global_config/brag/assets/sfx/casino/card-shove-3.ogg +0 -0
  169. package/skills/global_config/brag/assets/sfx/casino/card-shove-4.ogg +0 -0
  170. package/skills/global_config/brag/assets/sfx/casino/card-shuffle.ogg +0 -0
  171. package/skills/global_config/brag/assets/sfx/casino/card-slide-1.ogg +0 -0
  172. package/skills/global_config/brag/assets/sfx/casino/card-slide-2.ogg +0 -0
  173. package/skills/global_config/brag/assets/sfx/casino/card-slide-3.ogg +0 -0
  174. package/skills/global_config/brag/assets/sfx/casino/card-slide-4.ogg +0 -0
  175. package/skills/global_config/brag/assets/sfx/casino/card-slide-5.ogg +0 -0
  176. package/skills/global_config/brag/assets/sfx/casino/card-slide-6.ogg +0 -0
  177. package/skills/global_config/brag/assets/sfx/casino/card-slide-7.ogg +0 -0
  178. package/skills/global_config/brag/assets/sfx/casino/card-slide-8.ogg +0 -0
  179. package/skills/global_config/brag/assets/sfx/casino/cards-pack-open-1.ogg +0 -0
  180. package/skills/global_config/brag/assets/sfx/casino/cards-pack-open-2.ogg +0 -0
  181. package/skills/global_config/brag/assets/sfx/casino/chip-lay-1.ogg +0 -0
  182. package/skills/global_config/brag/assets/sfx/casino/chip-lay-2.ogg +0 -0
  183. package/skills/global_config/brag/assets/sfx/casino/chip-lay-3.ogg +0 -0
  184. package/skills/global_config/brag/assets/sfx/casino/chips-collide-1.ogg +0 -0
  185. package/skills/global_config/brag/assets/sfx/casino/chips-collide-2.ogg +0 -0
  186. package/skills/global_config/brag/assets/sfx/casino/chips-collide-3.ogg +0 -0
  187. package/skills/global_config/brag/assets/sfx/casino/chips-collide-4.ogg +0 -0
  188. package/skills/global_config/brag/assets/sfx/casino/chips-handle-1.ogg +0 -0
  189. package/skills/global_config/brag/assets/sfx/casino/chips-handle-2.ogg +0 -0
  190. package/skills/global_config/brag/assets/sfx/casino/chips-handle-3.ogg +0 -0
  191. package/skills/global_config/brag/assets/sfx/casino/chips-handle-4.ogg +0 -0
  192. package/skills/global_config/brag/assets/sfx/casino/chips-handle-6.ogg +0 -0
  193. package/skills/global_config/brag/assets/sfx/casino/chips-stack-1.ogg +0 -0
  194. package/skills/global_config/brag/assets/sfx/casino/chips-stack-2.ogg +0 -0
  195. package/skills/global_config/brag/assets/sfx/casino/chips-stack-3.ogg +0 -0
  196. package/skills/global_config/brag/assets/sfx/casino/chips-stack-4.ogg +0 -0
  197. package/skills/global_config/brag/assets/sfx/casino/chips-stack-5.ogg +0 -0
  198. package/skills/global_config/brag/assets/sfx/casino/chips-stack-6.ogg +0 -0
  199. package/skills/global_config/brag/assets/sfx/casino/dice-grab-1.ogg +0 -0
  200. package/skills/global_config/brag/assets/sfx/casino/dice-grab-2.ogg +0 -0
  201. package/skills/global_config/brag/assets/sfx/casino/dice-shake-1.ogg +0 -0
  202. package/skills/global_config/brag/assets/sfx/casino/dice-shake-2.ogg +0 -0
  203. package/skills/global_config/brag/assets/sfx/casino/dice-shake-3.ogg +0 -0
  204. package/skills/global_config/brag/assets/sfx/casino/dice-throw-1.ogg +0 -0
  205. package/skills/global_config/brag/assets/sfx/casino/dice-throw-2.ogg +0 -0
  206. package/skills/global_config/brag/assets/sfx/casino/dice-throw-3.ogg +0 -0
  207. package/skills/global_config/brag/assets/sfx/casino/die-throw-1.ogg +0 -0
  208. package/skills/global_config/brag/assets/sfx/casino/die-throw-2.ogg +0 -0
  209. package/skills/global_config/brag/assets/sfx/casino/die-throw-3.ogg +0 -0
  210. package/skills/global_config/brag/assets/sfx/casino/die-throw-4.ogg +0 -0
  211. package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_000.ogg +0 -0
  212. package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_003.ogg +0 -0
  213. package/skills/global_config/brag/assets/sfx/impact/footstep_carpet_004.ogg +0 -0
  214. package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_000.ogg +0 -0
  215. package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_001.ogg +0 -0
  216. package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_002.ogg +0 -0
  217. package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_003.ogg +0 -0
  218. package/skills/global_config/brag/assets/sfx/impact/footstep_concrete_004.ogg +0 -0
  219. package/skills/global_config/brag/assets/sfx/impact/footstep_grass_000.ogg +0 -0
  220. package/skills/global_config/brag/assets/sfx/impact/footstep_grass_001.ogg +0 -0
  221. package/skills/global_config/brag/assets/sfx/impact/footstep_grass_002.ogg +0 -0
  222. package/skills/global_config/brag/assets/sfx/impact/footstep_grass_003.ogg +0 -0
  223. package/skills/global_config/brag/assets/sfx/impact/footstep_grass_004.ogg +0 -0
  224. package/skills/global_config/brag/assets/sfx/impact/footstep_snow_000.ogg +0 -0
  225. package/skills/global_config/brag/assets/sfx/impact/footstep_snow_001.ogg +0 -0
  226. package/skills/global_config/brag/assets/sfx/impact/footstep_snow_002.ogg +0 -0
  227. package/skills/global_config/brag/assets/sfx/impact/footstep_snow_003.ogg +0 -0
  228. package/skills/global_config/brag/assets/sfx/impact/footstep_snow_004.ogg +0 -0
  229. package/skills/global_config/brag/assets/sfx/impact/footstep_wood_000.ogg +0 -0
  230. package/skills/global_config/brag/assets/sfx/impact/footstep_wood_001.ogg +0 -0
  231. package/skills/global_config/brag/assets/sfx/impact/footstep_wood_002.ogg +0 -0
  232. package/skills/global_config/brag/assets/sfx/impact/footstep_wood_003.ogg +0 -0
  233. package/skills/global_config/brag/assets/sfx/impact/footstep_wood_004.ogg +0 -0
  234. package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_000.ogg +0 -0
  235. package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_003.ogg +0 -0
  236. package/skills/global_config/brag/assets/sfx/impact/impactBell_heavy_004.ogg +0 -0
  237. package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_000.ogg +0 -0
  238. package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_001.ogg +0 -0
  239. package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_002.ogg +0 -0
  240. package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_003.ogg +0 -0
  241. package/skills/global_config/brag/assets/sfx/impact/impactGeneric_light_004.ogg +0 -0
  242. package/skills/global_config/brag/assets/sfx/impact/impactGlass_heavy_002.ogg +0 -0
  243. package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_001.ogg +0 -0
  244. package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_002.ogg +0 -0
  245. package/skills/global_config/brag/assets/sfx/impact/impactGlass_light_003.ogg +0 -0
  246. package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_000.ogg +0 -0
  247. package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_002.ogg +0 -0
  248. package/skills/global_config/brag/assets/sfx/impact/impactGlass_medium_004.ogg +0 -0
  249. package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_000.ogg +0 -0
  250. package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_002.ogg +0 -0
  251. package/skills/global_config/brag/assets/sfx/impact/impactMetal_heavy_004.ogg +0 -0
  252. package/skills/global_config/brag/assets/sfx/impact/impactMetal_light_002.ogg +0 -0
  253. package/skills/global_config/brag/assets/sfx/impact/impactMetal_light_003.ogg +0 -0
  254. package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_000.ogg +0 -0
  255. package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_001.ogg +0 -0
  256. package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_002.ogg +0 -0
  257. package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_003.ogg +0 -0
  258. package/skills/global_config/brag/assets/sfx/impact/impactMetal_medium_004.ogg +0 -0
  259. package/skills/global_config/brag/assets/sfx/impact/impactMining_001.ogg +0 -0
  260. package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_000.ogg +0 -0
  261. package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_001.ogg +0 -0
  262. package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_002.ogg +0 -0
  263. package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_003.ogg +0 -0
  264. package/skills/global_config/brag/assets/sfx/impact/impactPlank_medium_004.ogg +0 -0
  265. package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_000.ogg +0 -0
  266. package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_001.ogg +0 -0
  267. package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_002.ogg +0 -0
  268. package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_003.ogg +0 -0
  269. package/skills/global_config/brag/assets/sfx/impact/impactPlate_heavy_004.ogg +0 -0
  270. package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_000.ogg +0 -0
  271. package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_001.ogg +0 -0
  272. package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_002.ogg +0 -0
  273. package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_003.ogg +0 -0
  274. package/skills/global_config/brag/assets/sfx/impact/impactPlate_light_004.ogg +0 -0
  275. package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_000.ogg +0 -0
  276. package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_001.ogg +0 -0
  277. package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_002.ogg +0 -0
  278. package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_003.ogg +0 -0
  279. package/skills/global_config/brag/assets/sfx/impact/impactPlate_medium_004.ogg +0 -0
  280. package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_000.ogg +0 -0
  281. package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_001.ogg +0 -0
  282. package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_002.ogg +0 -0
  283. package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_003.ogg +0 -0
  284. package/skills/global_config/brag/assets/sfx/impact/impactPunch_heavy_004.ogg +0 -0
  285. package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_000.ogg +0 -0
  286. package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_001.ogg +0 -0
  287. package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_002.ogg +0 -0
  288. package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_003.ogg +0 -0
  289. package/skills/global_config/brag/assets/sfx/impact/impactPunch_medium_004.ogg +0 -0
  290. package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_000.ogg +0 -0
  291. package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_001.ogg +0 -0
  292. package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_002.ogg +0 -0
  293. package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_003.ogg +0 -0
  294. package/skills/global_config/brag/assets/sfx/impact/impactSoft_heavy_004.ogg +0 -0
  295. package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_000.ogg +0 -0
  296. package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_001.ogg +0 -0
  297. package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_002.ogg +0 -0
  298. package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_003.ogg +0 -0
  299. package/skills/global_config/brag/assets/sfx/impact/impactSoft_medium_004.ogg +0 -0
  300. package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_000.ogg +0 -0
  301. package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_001.ogg +0 -0
  302. package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_002.ogg +0 -0
  303. package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_003.ogg +0 -0
  304. package/skills/global_config/brag/assets/sfx/impact/impactTin_medium_004.ogg +0 -0
  305. package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_000.ogg +0 -0
  306. package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_001.ogg +0 -0
  307. package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_002.ogg +0 -0
  308. package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_003.ogg +0 -0
  309. package/skills/global_config/brag/assets/sfx/impact/impactWood_heavy_004.ogg +0 -0
  310. package/skills/global_config/brag/assets/sfx/impact/impactWood_light_000.ogg +0 -0
  311. package/skills/global_config/brag/assets/sfx/impact/impactWood_light_001.ogg +0 -0
  312. package/skills/global_config/brag/assets/sfx/impact/impactWood_light_002.ogg +0 -0
  313. package/skills/global_config/brag/assets/sfx/impact/impactWood_light_003.ogg +0 -0
  314. package/skills/global_config/brag/assets/sfx/impact/impactWood_light_004.ogg +0 -0
  315. package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_000.ogg +0 -0
  316. package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_001.ogg +0 -0
  317. package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_002.ogg +0 -0
  318. package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_003.ogg +0 -0
  319. package/skills/global_config/brag/assets/sfx/impact/impactWood_medium_004.ogg +0 -0
  320. package/skills/global_config/brag/assets/sfx/interface/bong_001.ogg +0 -0
  321. package/skills/global_config/brag/assets/sfx/interface/click_001.ogg +0 -0
  322. package/skills/global_config/brag/assets/sfx/interface/click_002.ogg +0 -0
  323. package/skills/global_config/brag/assets/sfx/interface/click_003.ogg +0 -0
  324. package/skills/global_config/brag/assets/sfx/interface/click_004.ogg +0 -0
  325. package/skills/global_config/brag/assets/sfx/interface/click_005.ogg +0 -0
  326. package/skills/global_config/brag/assets/sfx/interface/drop_001.ogg +0 -0
  327. package/skills/global_config/brag/assets/sfx/interface/drop_002.ogg +0 -0
  328. package/skills/global_config/brag/assets/sfx/interface/drop_003.ogg +0 -0
  329. package/skills/global_config/brag/assets/sfx/interface/error_005.ogg +0 -0
  330. package/skills/global_config/brag/assets/sfx/interface/error_006.ogg +0 -0
  331. package/skills/global_config/brag/assets/sfx/interface/glitch_002.ogg +0 -0
  332. package/skills/global_config/brag/assets/sfx/interface/glitch_004.ogg +0 -0
  333. package/skills/global_config/brag/assets/sfx/interface/select_008.ogg +0 -0
  334. package/skills/global_config/brag/assets/sfx/interface/switch_001.ogg +0 -0
  335. package/skills/global_config/brag/assets/sfx/interface/switch_002.ogg +0 -0
  336. package/skills/global_config/brag/assets/sfx/interface/switch_004.ogg +0 -0
  337. package/skills/global_config/brag/assets/sfx/interface/switch_005.ogg +0 -0
  338. package/skills/global_config/brag/assets/sfx/interface/switch_006.ogg +0 -0
  339. package/skills/global_config/brag/assets/sfx/interface/switch_007.ogg +0 -0
  340. package/skills/global_config/brag/assets/sfx/keyboard/keypress-001.wav +0 -0
  341. package/skills/global_config/brag/assets/sfx/keyboard/keypress-002.wav +0 -0
  342. package/skills/global_config/brag/assets/sfx/keyboard/keypress-003.wav +0 -0
  343. package/skills/global_config/brag/assets/sfx/keyboard/keypress-004.wav +0 -0
  344. package/skills/global_config/brag/assets/sfx/keyboard/keypress-005.wav +0 -0
  345. package/skills/global_config/brag/assets/sfx/keyboard/keypress-006.wav +0 -0
  346. package/skills/global_config/brag/assets/sfx/keyboard/keypress-007.wav +0 -0
  347. package/skills/global_config/brag/assets/sfx/keyboard/keypress-008.wav +0 -0
  348. package/skills/global_config/brag/assets/sfx/keyboard/keypress-009.wav +0 -0
  349. package/skills/global_config/brag/assets/sfx/keyboard/keypress-010.wav +0 -0
  350. package/skills/global_config/brag/assets/sfx/keyboard/keypress-011.wav +0 -0
  351. package/skills/global_config/brag/assets/sfx/keyboard/keypress-012.wav +0 -0
  352. package/skills/global_config/brag/assets/sfx/keyboard/keypress-013.wav +0 -0
  353. package/skills/global_config/brag/assets/sfx/keyboard/keypress-014.wav +0 -0
  354. package/skills/global_config/brag/assets/sfx/keyboard/keypress-015.wav +0 -0
  355. package/skills/global_config/brag/assets/sfx/keyboard/keypress-016.wav +0 -0
  356. package/skills/global_config/brag/assets/sfx/keyboard/keypress-017.wav +0 -0
  357. package/skills/global_config/brag/assets/sfx/keyboard/keypress-018.wav +0 -0
  358. package/skills/global_config/brag/assets/sfx/keyboard/keypress-019.wav +0 -0
  359. package/skills/global_config/brag/assets/sfx/keyboard/keypress-020.wav +0 -0
  360. package/skills/global_config/brag/assets/sfx/keyboard/keypress-021.wav +0 -0
  361. package/skills/global_config/brag/assets/sfx/keyboard/keypress-022.wav +0 -0
  362. package/skills/global_config/brag/assets/sfx/keyboard/keypress-023.wav +0 -0
  363. package/skills/global_config/brag/assets/sfx/keyboard/keypress-024.wav +0 -0
  364. package/skills/global_config/brag/assets/sfx/keyboard/keypress-025.wav +0 -0
  365. package/skills/global_config/brag/assets/sfx/keyboard/keypress-026.wav +0 -0
  366. package/skills/global_config/brag/assets/sfx/keyboard/keypress-027.wav +0 -0
  367. package/skills/global_config/brag/assets/sfx/keyboard/keypress-028.wav +0 -0
  368. package/skills/global_config/brag/assets/sfx/keyboard/keypress-029.wav +0 -0
  369. package/skills/global_config/brag/assets/sfx/keyboard/keypress-030.wav +0 -0
  370. package/skills/global_config/brag/assets/sfx/keyboard/keypress-031.wav +0 -0
  371. package/skills/global_config/brag/assets/sfx/keyboard/keypress-032.wav +0 -0
  372. package/skills/global_config/brag/assets/sfx/sfx-analysis.json +15584 -0
  373. package/skills/global_config/brag/assets/sfx/sfx-analysis.md +75 -0
  374. package/skills/global_config/brag/assets/sfx/ui/click1.ogg +0 -0
  375. package/skills/global_config/brag/assets/sfx/ui/click2.ogg +0 -0
  376. package/skills/global_config/brag/assets/sfx/ui/click3.ogg +0 -0
  377. package/skills/global_config/brag/assets/sfx/ui/click4.ogg +0 -0
  378. package/skills/global_config/brag/assets/sfx/ui/click5.ogg +0 -0
  379. package/skills/global_config/brag/assets/sfx/ui/mouseclick1.ogg +0 -0
  380. package/skills/global_config/brag/assets/sfx/ui/rollover1.ogg +0 -0
  381. package/skills/global_config/brag/assets/sfx/ui/rollover2.ogg +0 -0
  382. package/skills/global_config/brag/assets/sfx/ui/rollover4.ogg +0 -0
  383. package/skills/global_config/brag/assets/sfx/ui/rollover5.ogg +0 -0
  384. package/skills/global_config/brag/assets/sfx/ui/switch1.ogg +0 -0
  385. package/skills/global_config/brag/assets/sfx/ui/switch10.ogg +0 -0
  386. package/skills/global_config/brag/assets/sfx/ui/switch11.ogg +0 -0
  387. package/skills/global_config/brag/assets/sfx/ui/switch12.ogg +0 -0
  388. package/skills/global_config/brag/assets/sfx/ui/switch13.ogg +0 -0
  389. package/skills/global_config/brag/assets/sfx/ui/switch14.ogg +0 -0
  390. package/skills/global_config/brag/assets/sfx/ui/switch15.ogg +0 -0
  391. package/skills/global_config/brag/assets/sfx/ui/switch16.ogg +0 -0
  392. package/skills/global_config/brag/assets/sfx/ui/switch17.ogg +0 -0
  393. package/skills/global_config/brag/assets/sfx/ui/switch18.ogg +0 -0
  394. package/skills/global_config/brag/assets/sfx/ui/switch19.ogg +0 -0
  395. package/skills/global_config/brag/assets/sfx/ui/switch2.ogg +0 -0
  396. package/skills/global_config/brag/assets/sfx/ui/switch20.ogg +0 -0
  397. package/skills/global_config/brag/assets/sfx/ui/switch21.ogg +0 -0
  398. package/skills/global_config/brag/assets/sfx/ui/switch22.ogg +0 -0
  399. package/skills/global_config/brag/assets/sfx/ui/switch23.ogg +0 -0
  400. package/skills/global_config/brag/assets/sfx/ui/switch24.ogg +0 -0
  401. package/skills/global_config/brag/assets/sfx/ui/switch25.ogg +0 -0
  402. package/skills/global_config/brag/assets/sfx/ui/switch26.ogg +0 -0
  403. package/skills/global_config/brag/assets/sfx/ui/switch27.ogg +0 -0
  404. package/skills/global_config/brag/assets/sfx/ui/switch28.ogg +0 -0
  405. package/skills/global_config/brag/assets/sfx/ui/switch29.ogg +0 -0
  406. package/skills/global_config/brag/assets/sfx/ui/switch3.ogg +0 -0
  407. package/skills/global_config/brag/assets/sfx/ui/switch30.ogg +0 -0
  408. package/skills/global_config/brag/assets/sfx/ui/switch31.ogg +0 -0
  409. package/skills/global_config/brag/assets/sfx/ui/switch32.ogg +0 -0
  410. package/skills/global_config/brag/assets/sfx/ui/switch33.ogg +0 -0
  411. package/skills/global_config/brag/assets/sfx/ui/switch34.ogg +0 -0
  412. package/skills/global_config/brag/assets/sfx/ui/switch35.ogg +0 -0
  413. package/skills/global_config/brag/assets/sfx/ui/switch36.ogg +0 -0
  414. package/skills/global_config/brag/assets/sfx/ui/switch37.ogg +0 -0
  415. package/skills/global_config/brag/assets/sfx/ui/switch38.ogg +0 -0
  416. package/skills/global_config/brag/assets/sfx/ui/switch4.ogg +0 -0
  417. package/skills/global_config/brag/assets/sfx/ui/switch5.ogg +0 -0
  418. package/skills/global_config/brag/assets/sfx/ui/switch6.ogg +0 -0
  419. package/skills/global_config/brag/assets/sfx/ui/switch7.ogg +0 -0
  420. package/skills/global_config/brag/assets/sfx/ui/switch8.ogg +0 -0
  421. package/skills/global_config/brag/assets/sfx/ui/switch9.ogg +0 -0
  422. package/skills/global_config/brag/references/audio.md +307 -0
  423. package/skills/global_config/brag/references/step-1-inspect.md +133 -0
  424. package/skills/global_config/brag/references/step-2-plan.md +234 -0
  425. package/skills/global_config/brag/references/step-3-compose.md +210 -0
  426. package/skills/global_config/brag/references/step-4-deliver.md +168 -0
  427. package/skills/global_config/brag/references/tones.md +231 -0
  428. package/skills/global_config/brag/scripts/analyze_music_cues.py +309 -0
  429. package/skills/global_config/brag/scripts/pyproject.toml +14 -0
  430. package/skills/global_config/brag/scripts/uv.lock +819 -0
  431. package/skills/global_config/deja-memory/SKILL.md +42 -0
  432. package/skills/global_config/editable-design/LICENSE +202 -0
  433. package/skills/global_config/editable-design/README.md +34 -0
  434. package/skills/global_config/editable-design/SKILL.md +630 -0
  435. package/skills/global_config/editable-design/THIRD_PARTY_NOTICES.md +10 -0
  436. package/skills/global_config/editable-design/agents/openai.yaml +4 -0
  437. package/skills/global_config/editable-design/assets/editor/layer-editor.css +262 -0
  438. package/skills/global_config/editable-design/assets/editor/layer-editor.js +1929 -0
  439. package/skills/global_config/editable-design/assets/poster-starter/README.md +92 -0
  440. package/skills/global_config/editable-design/assets/poster-starter/assets/.gitkeep +0 -0
  441. package/skills/global_config/editable-design/assets/poster-starter/index.html +91 -0
  442. package/skills/global_config/editable-design/assets/poster-starter/poster.json +6 -0
  443. package/skills/global_config/editable-design/assets/poster-starter/reference/.gitkeep +1 -0
  444. package/skills/global_config/editable-design/assets/replay/icons/assets.png +0 -0
  445. package/skills/global_config/editable-design/assets/replay/icons/html.png +0 -0
  446. package/skills/global_config/editable-design/assets/replay/icons/input.png +0 -0
  447. package/skills/global_config/editable-design/assets/replay/icons/layers.png +0 -0
  448. package/skills/global_config/editable-design/assets/replay/icons/plan.png +0 -0
  449. package/skills/global_config/editable-design/assets/replay/icons/reference.png +0 -0
  450. package/skills/global_config/editable-design/assets/replay/icons/review.png +0 -0
  451. package/skills/global_config/editable-design/assets/replay/index.html +59 -0
  452. package/skills/global_config/editable-design/assets/replay/replay-motion.js +410 -0
  453. package/skills/global_config/editable-design/assets/replay/replay.css +380 -0
  454. package/skills/global_config/editable-design/assets/replay/replay.js +374 -0
  455. package/skills/global_config/editable-design/font-kit/package-lock.json +115 -0
  456. package/skills/global_config/editable-design/font-kit/package.json +19 -0
  457. package/skills/global_config/editable-design/pack.sh +20 -0
  458. package/skills/global_config/editable-design/references/asset-architecture.md +72 -0
  459. package/skills/global_config/editable-design/references/editor-pitfalls.md +70 -0
  460. package/skills/global_config/editable-design/references/editor-runtime.md +131 -0
  461. package/skills/global_config/editable-design/references/font-system.md +89 -0
  462. package/skills/global_config/editable-design/references/imagery.md +145 -0
  463. package/skills/global_config/editable-design/references/layout-typography.md +116 -0
  464. package/skills/global_config/editable-design/references/replay-contract.md +169 -0
  465. package/skills/global_config/editable-design/scripts/_browser.mjs +247 -0
  466. package/skills/global_config/editable-design/scripts/bake.mjs +87 -0
  467. package/skills/global_config/editable-design/scripts/build-replay.mjs +316 -0
  468. package/skills/global_config/editable-design/scripts/check-contract.mjs +293 -0
  469. package/skills/global_config/editable-design/scripts/check-fonts.sh +252 -0
  470. package/skills/global_config/editable-design/scripts/check-poster.sh +70 -0
  471. package/skills/global_config/editable-design/scripts/doctor.sh +78 -0
  472. package/skills/global_config/editable-design/scripts/explode.mjs +115 -0
  473. package/skills/global_config/editable-design/scripts/font-kit.mjs +187 -0
  474. package/skills/global_config/editable-design/scripts/import-asset.sh +23 -0
  475. package/skills/global_config/editable-design/scripts/init-poster.sh +64 -0
  476. package/skills/global_config/editable-design/scripts/install-font-kit.sh +13 -0
  477. package/skills/global_config/editable-design/scripts/package-lock.json +334 -0
  478. package/skills/global_config/editable-design/scripts/package.json +14 -0
  479. package/skills/global_config/editable-design/scripts/remove-chroma-key.py +201 -0
  480. package/skills/global_config/editable-design/scripts/render-poster.sh +202 -0
  481. package/skills/global_config/editable-design/scripts/trace.sh +159 -0
  482. package/skills/global_config/editable-design/scripts/verify-replay.mjs +97 -0
  483. package/skills/global_config/editable-design/scripts/verify.mjs +782 -0
  484. package/skills/global_config/editable-design/scripts/wire-editor.mjs +104 -0
  485. package/skills/global_config/editable-design/tests/fixtures/small-explode/index.html +86 -0
  486. 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/&amp;/\&/g; s/&lt;/</g; s/&gt;/>/g; s/&quot;/"/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);