aiox-core 5.0.3 → 5.0.4

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 (468) hide show
  1. package/.aiox-core/core/execution/predictive-pipeline.js +1283 -0
  2. package/.aiox-core/core/memory/decision-memory.js +564 -0
  3. package/.aiox-core/data/entity-registry.yaml +1068 -1028
  4. package/.aiox-core/data/registry-update-log.jsonl +2 -2
  5. package/.aiox-core/development/templates/service-template/README.md.hbs +158 -158
  6. package/.aiox-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
  7. package/.aiox-core/development/templates/service-template/client.ts.hbs +403 -403
  8. package/.aiox-core/development/templates/service-template/errors.ts.hbs +182 -182
  9. package/.aiox-core/development/templates/service-template/index.ts.hbs +120 -120
  10. package/.aiox-core/development/templates/service-template/package.json.hbs +87 -87
  11. package/.aiox-core/development/templates/service-template/types.ts.hbs +145 -145
  12. package/.aiox-core/development/templates/squad-template/LICENSE +21 -21
  13. package/.aiox-core/infrastructure/templates/aiox-sync.yaml.template +182 -182
  14. package/.aiox-core/infrastructure/templates/coderabbit.yaml.template +279 -279
  15. package/.aiox-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
  16. package/.aiox-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
  17. package/.aiox-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
  18. package/.aiox-core/infrastructure/templates/gitignore/gitignore-aiox-base.tmpl +63 -63
  19. package/.aiox-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
  20. package/.aiox-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
  21. package/.aiox-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
  22. package/.aiox-core/install-manifest.yaml +63 -55
  23. package/.aiox-core/local-config.yaml.template +71 -71
  24. package/.aiox-core/monitor/hooks/lib/__init__.py +1 -1
  25. package/.aiox-core/monitor/hooks/lib/enrich.py +58 -58
  26. package/.aiox-core/monitor/hooks/lib/send_event.py +47 -47
  27. package/.aiox-core/monitor/hooks/notification.py +29 -29
  28. package/.aiox-core/monitor/hooks/post_tool_use.py +45 -45
  29. package/.aiox-core/monitor/hooks/pre_compact.py +29 -29
  30. package/.aiox-core/monitor/hooks/pre_tool_use.py +40 -40
  31. package/.aiox-core/monitor/hooks/stop.py +29 -29
  32. package/.aiox-core/monitor/hooks/subagent_stop.py +29 -29
  33. package/.aiox-core/monitor/hooks/user_prompt_submit.py +38 -38
  34. package/.aiox-core/product/templates/adr.hbs +125 -125
  35. package/.aiox-core/product/templates/dbdr.hbs +241 -241
  36. package/.aiox-core/product/templates/epic.hbs +212 -212
  37. package/.aiox-core/product/templates/pmdr.hbs +186 -186
  38. package/.aiox-core/product/templates/prd-v2.0.hbs +216 -216
  39. package/.aiox-core/product/templates/prd.hbs +201 -201
  40. package/.aiox-core/product/templates/story.hbs +263 -263
  41. package/.aiox-core/product/templates/task.hbs +170 -170
  42. package/.aiox-core/product/templates/tmpl-comment-on-examples.sql +158 -158
  43. package/.aiox-core/product/templates/tmpl-migration-script.sql +91 -91
  44. package/.aiox-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
  45. package/.aiox-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
  46. package/.aiox-core/product/templates/tmpl-rls-roles.sql +135 -135
  47. package/.aiox-core/product/templates/tmpl-rls-simple.sql +77 -77
  48. package/.aiox-core/product/templates/tmpl-rls-tenant.sql +152 -152
  49. package/.aiox-core/product/templates/tmpl-rollback-script.sql +77 -77
  50. package/.aiox-core/product/templates/tmpl-seed-data.sql +140 -140
  51. package/.aiox-core/product/templates/tmpl-smoke-test.sql +16 -16
  52. package/.aiox-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
  53. package/.aiox-core/product/templates/tmpl-stored-proc.sql +140 -140
  54. package/.aiox-core/product/templates/tmpl-trigger.sql +152 -152
  55. package/.aiox-core/product/templates/tmpl-view-materialized.sql +133 -133
  56. package/.aiox-core/product/templates/tmpl-view.sql +177 -177
  57. package/.aiox-core/scripts/pm.sh +0 -0
  58. package/.claude/hooks/enforce-architecture-first.py +196 -196
  59. package/.claude/hooks/mind-clone-governance.py +192 -192
  60. package/.claude/hooks/read-protection.py +151 -151
  61. package/.claude/hooks/slug-validation.py +176 -176
  62. package/.claude/hooks/sql-governance.py +182 -182
  63. package/.claude/hooks/write-path-validation.py +194 -194
  64. package/LICENSE +33 -33
  65. package/bin/aiox-graph.js +0 -0
  66. package/bin/aiox-minimal.js +0 -0
  67. package/bin/aiox.js +0 -0
  68. package/package.json +1 -1
  69. package/packages/aiox-install/bin/aiox-install.js +0 -0
  70. package/packages/aiox-install/bin/edmcp.js +0 -0
  71. package/packages/aiox-pro-cli/bin/aiox-pro.js +0 -0
  72. package/packages/installer/src/wizard/pro-setup.js +28 -0
  73. package/pro/README.md +66 -66
  74. package/pro/feature-registry.yaml +225 -223
  75. package/pro/license/license-api.js +701 -679
  76. package/pro/package.json +39 -39
  77. package/pro/pro-config.yaml +63 -63
  78. package/pro/squads/README.md +24 -24
  79. package/pro/squads/design/HEADLINE.md +3 -3
  80. package/pro/squads/design/README.md +109 -109
  81. package/pro/squads/design/agents/brad-frost.md +1097 -1097
  82. package/pro/squads/design/agents/dan-mall.md +857 -857
  83. package/pro/squads/design/agents/dave-malouf.md +2272 -2272
  84. package/pro/squads/design/agents/design-chief.md +114 -114
  85. package/pro/squads/design/agents/ds-foundations-lead.md +194 -194
  86. package/pro/squads/design/agents/ds-token-architect.md +361 -361
  87. package/pro/squads/design/agents/nano-banana-generator.md +162 -162
  88. package/pro/squads/design/agents/storybook-expert.md +809 -809
  89. package/pro/squads/design/checklists/atomic-refactor-checklist.md +299 -299
  90. package/pro/squads/design/checklists/component-adaptation-checklist.md +81 -81
  91. package/pro/squads/design/checklists/design-fidelity-checklist.md +283 -283
  92. package/pro/squads/design/checklists/design-handoff-checklist.md +55 -55
  93. package/pro/squads/design/checklists/design-team-health-checklist.md +454 -454
  94. package/pro/squads/design/checklists/designops-maturity-checklist.md +518 -518
  95. package/pro/squads/design/checklists/ds-a11y-release-gate-checklist.md +45 -45
  96. package/pro/squads/design/checklists/ds-accessibility-wcag-checklist.md +147 -147
  97. package/pro/squads/design/checklists/ds-component-quality-checklist.md +150 -150
  98. package/pro/squads/design/checklists/ds-critical-eye-review-checklist.md +147 -147
  99. package/pro/squads/design/checklists/ds-migration-readiness-checklist.md +99 -99
  100. package/pro/squads/design/checklists/ds-pattern-audit-checklist.md +164 -164
  101. package/pro/squads/design/checklists/reading-accessibility-checklist.md +275 -275
  102. package/pro/squads/design/checklists/token-mapping-checklist.md +107 -107
  103. package/pro/squads/design/config/coding-standards.md +286 -286
  104. package/pro/squads/design/config/source-tree.md +59 -59
  105. package/pro/squads/design/config/tech-stack.md +48 -48
  106. package/pro/squads/design/config.yaml +204 -204
  107. package/pro/squads/design/data/agentic-design-systems-guide.md +46 -46
  108. package/pro/squads/design/data/agentic-ds-principles.md +100 -100
  109. package/pro/squads/design/data/atomic-design-principles.md +108 -108
  110. package/pro/squads/design/data/atomic-refactor-rules.md +582 -582
  111. package/pro/squads/design/data/base-component-specs.md +972 -972
  112. package/pro/squads/design/data/brad-frost-analysis-extract-implicit.yaml +270 -270
  113. package/pro/squads/design/data/brad-frost-analysis-find-0.8.yaml +176 -176
  114. package/pro/squads/design/data/brad-frost-analysis-qa-report.yaml +168 -168
  115. package/pro/squads/design/data/brad-frost-dna.yaml +713 -713
  116. package/pro/squads/design/data/capability-tools.yaml +124 -124
  117. package/pro/squads/design/data/component-adaptation-changelog.md +318 -318
  118. package/pro/squads/design/data/consolidation-algorithms.md +168 -168
  119. package/pro/squads/design/data/critical-eye-scoring-rules.yaml +240 -240
  120. package/pro/squads/design/data/design-token-best-practices.md +107 -107
  121. package/pro/squads/design/data/design-tokens-spec.yaml +418 -418
  122. package/pro/squads/design/data/ds-reference-architectures.md +93 -93
  123. package/pro/squads/design/data/f2-qa-report.md +168 -168
  124. package/pro/squads/design/data/f3-derived-components-changelog.md +100 -100
  125. package/pro/squads/design/data/f3-qa-report.md +208 -208
  126. package/pro/squads/design/data/figma-base-components-raw.md +101 -101
  127. package/pro/squads/design/data/figma-tokens-raw.md +1548 -1548
  128. package/pro/squads/design/data/fluent2-design-principles.md +114 -114
  129. package/pro/squads/design/data/high-retention-reading-guide.md +349 -349
  130. package/pro/squads/design/data/integration-patterns.md +207 -207
  131. package/pro/squads/design/data/internal-quality-chain.yaml +48 -48
  132. package/pro/squads/design/data/motion-tokens-guide.md +202 -202
  133. package/pro/squads/design/data/roi-calculation-guide.md +142 -142
  134. package/pro/squads/design/data/token-mapping-reference.md +213 -213
  135. package/pro/squads/design/data/w3c-dtcg-spec-reference.md +149 -149
  136. package/pro/squads/design/data/wcag-compliance-guide.md +267 -267
  137. package/pro/squads/design/docs/AUDIT_REPORT.md +97 -97
  138. package/pro/squads/design/docs/DS-CURATION-PIPELINE-PROPOSAL.md +577 -577
  139. package/pro/squads/design/docs/UPGRADE_PLAN.md +618 -618
  140. package/pro/squads/design/docs/brad-frost-research-validation.md +372 -372
  141. package/pro/squads/design/docs/dave-malouf-research-validation.md +391 -391
  142. package/pro/squads/design/docs/tool-discovery-report.md +87 -87
  143. package/pro/squads/design/docs/tool-integration-plan.md +44 -44
  144. package/pro/squads/design/protocols/ai-first-governance.md +56 -56
  145. package/pro/squads/design/protocols/governance-execution-boundary.md +59 -59
  146. package/pro/squads/design/protocols/handoff.md +60 -60
  147. package/pro/squads/design/rules/.claude-rules.md +88 -88
  148. package/pro/squads/design/scripts/design-system/curate_colors.cjs +447 -447
  149. package/pro/squads/design/scripts/design-system/curate_components.cjs +217 -217
  150. package/pro/squads/design/scripts/design-system/curate_radius.cjs +190 -190
  151. package/pro/squads/design/scripts/design-system/curate_shadows.cjs +208 -208
  152. package/pro/squads/design/scripts/design-system/curate_spacing.cjs +243 -243
  153. package/pro/squads/design/scripts/design-system/curate_typography.cjs +404 -404
  154. package/pro/squads/design/scripts/design-system/design-system-metadata.test.js +49 -49
  155. package/pro/squads/design/scripts/design-system/design_manifest_lib.cjs +142 -142
  156. package/pro/squads/design/scripts/design-system/fetch_page_images.cjs +195 -195
  157. package/pro/squads/design/scripts/design-system/generate_components_metadata.cjs +114 -114
  158. package/pro/squads/design/scripts/design-system/generate_curation_report.cjs +258 -258
  159. package/pro/squads/design/scripts/design-system/generate_tokens.cjs +342 -342
  160. package/pro/squads/design/scripts/design-system/sync_design_manifest.cjs +27 -27
  161. package/pro/squads/design/scripts/design-system/test_mcp_tools.cjs +232 -232
  162. package/pro/squads/design/scripts/design-system/validate_components_metadata.cjs +96 -96
  163. package/pro/squads/design/scripts/design-system/validate_curation.cjs +226 -226
  164. package/pro/squads/design/scripts/design-system/validate_design_manifest_drift.cjs +72 -72
  165. package/pro/squads/design/scripts/design-system/validate_mcp_skeleton.cjs +38 -38
  166. package/pro/squads/design/scripts/design-system/validate_registry.cjs +186 -186
  167. package/pro/squads/design/scripts/design-system/validate_task_checklist_bindings.cjs +78 -78
  168. package/pro/squads/design/scripts/dissect-artifact.cjs +806 -806
  169. package/pro/squads/design/scripts/validate-a11y-integration.cjs +40 -40
  170. package/pro/squads/design/scripts/validate-design-squad.py +411 -411
  171. package/pro/squads/design/squad.yaml +714 -714
  172. package/pro/squads/design/tasks/a11y-audit.md +340 -340
  173. package/pro/squads/design/tasks/aria-audit.md +525 -525
  174. package/pro/squads/design/tasks/atomic-refactor-execute.md +391 -391
  175. package/pro/squads/design/tasks/atomic-refactor-plan.md +262 -262
  176. package/pro/squads/design/tasks/audit-reading-experience.md +350 -350
  177. package/pro/squads/design/tasks/audit-tailwind-config.md +101 -101
  178. package/pro/squads/design/tasks/bootstrap-shadcn-library.md +96 -96
  179. package/pro/squads/design/tasks/bundle-audit.md +245 -245
  180. package/pro/squads/design/tasks/contrast-matrix.md +373 -373
  181. package/pro/squads/design/tasks/create-doc.md +135 -135
  182. package/pro/squads/design/tasks/dead-code-detection.md +329 -329
  183. package/pro/squads/design/tasks/design-compare.md +414 -414
  184. package/pro/squads/design/tasks/design-process-optimization.md +407 -407
  185. package/pro/squads/design/tasks/design-review-orchestration.md +99 -99
  186. package/pro/squads/design/tasks/design-team-scaling.md +407 -407
  187. package/pro/squads/design/tasks/design-tooling-audit.md +404 -404
  188. package/pro/squads/design/tasks/design-triage.md +89 -89
  189. package/pro/squads/design/tasks/designops-maturity-assessment.md +364 -364
  190. package/pro/squads/design/tasks/designops-metrics-setup.md +465 -465
  191. package/pro/squads/design/tasks/ds-agentic-audit.md +100 -100
  192. package/pro/squads/design/tasks/ds-agentic-setup.md +103 -103
  193. package/pro/squads/design/tasks/ds-audit-codebase.md +273 -273
  194. package/pro/squads/design/tasks/ds-build-component.md +349 -349
  195. package/pro/squads/design/tasks/ds-build-mcp-server.md +84 -84
  196. package/pro/squads/design/tasks/ds-calculate-roi.md +282 -282
  197. package/pro/squads/design/tasks/ds-compose-molecule.md +106 -106
  198. package/pro/squads/design/tasks/ds-consolidate-patterns.md +253 -253
  199. package/pro/squads/design/tasks/ds-context-contract.md +194 -194
  200. package/pro/squads/design/tasks/ds-critical-eye-compare.md +130 -130
  201. package/pro/squads/design/tasks/ds-critical-eye-decide.md +139 -139
  202. package/pro/squads/design/tasks/ds-critical-eye-inventory.md +111 -111
  203. package/pro/squads/design/tasks/ds-critical-eye-report.md +101 -101
  204. package/pro/squads/design/tasks/ds-critical-eye-score.md +109 -109
  205. package/pro/squads/design/tasks/ds-designops.md +99 -99
  206. package/pro/squads/design/tasks/ds-extend-pattern.md +91 -91
  207. package/pro/squads/design/tasks/ds-extract-tokens.md +312 -312
  208. package/pro/squads/design/tasks/ds-figma-pipeline.md +95 -95
  209. package/pro/squads/design/tasks/ds-fluent-audit.md +105 -105
  210. package/pro/squads/design/tasks/ds-fluent-build.md +110 -110
  211. package/pro/squads/design/tasks/ds-generate-ai-metadata.md +81 -81
  212. package/pro/squads/design/tasks/ds-generate-cursor-rules.md +74 -74
  213. package/pro/squads/design/tasks/ds-generate-documentation.md +101 -101
  214. package/pro/squads/design/tasks/ds-generate-migration-strategy.md +331 -331
  215. package/pro/squads/design/tasks/ds-generate-shock-report.md +323 -323
  216. package/pro/squads/design/tasks/ds-govern-a11y-compliance.md +93 -93
  217. package/pro/squads/design/tasks/ds-governance.md +187 -187
  218. package/pro/squads/design/tasks/ds-health-metrics.md +278 -278
  219. package/pro/squads/design/tasks/ds-integrate-squad.md +130 -130
  220. package/pro/squads/design/tasks/ds-integrate-workspace.md +100 -100
  221. package/pro/squads/design/tasks/ds-legacy-modernization.md +302 -302
  222. package/pro/squads/design/tasks/ds-mcp-status.md +65 -65
  223. package/pro/squads/design/tasks/ds-motion-audit.md +118 -118
  224. package/pro/squads/design/tasks/ds-multi-framework.md +96 -96
  225. package/pro/squads/design/tasks/ds-parallelization-gate.md +246 -246
  226. package/pro/squads/design/tasks/ds-query.md +90 -90
  227. package/pro/squads/design/tasks/ds-rebuild-artifact.md +369 -369
  228. package/pro/squads/design/tasks/ds-reverse-engineer.md +194 -194
  229. package/pro/squads/design/tasks/ds-scan-artifact.md +131 -131
  230. package/pro/squads/design/tasks/ds-setup-design-system.md +297 -297
  231. package/pro/squads/design/tasks/ds-sync-registry.md +287 -287
  232. package/pro/squads/design/tasks/ds-theme-multi-brand.md +90 -90
  233. package/pro/squads/design/tasks/ds-token-modes.md +108 -108
  234. package/pro/squads/design/tasks/ds-token-w3c-extract.md +105 -105
  235. package/pro/squads/design/tasks/ds-validate-ai-readiness.md +69 -69
  236. package/pro/squads/design/tasks/ds-visual-regression.md +130 -130
  237. package/pro/squads/design/tasks/execute-checklist.md +141 -141
  238. package/pro/squads/design/tasks/export-design-tokens-dtcg.md +97 -97
  239. package/pro/squads/design/tasks/f1-apply-foundations.md +154 -154
  240. package/pro/squads/design/tasks/f1-ingest-figma-tokens.md +130 -130
  241. package/pro/squads/design/tasks/f1-map-tokens-to-shadcn.md +145 -145
  242. package/pro/squads/design/tasks/f1-qa-foundations.md +95 -95
  243. package/pro/squads/design/tasks/f2-adapt-shadcn-components.md +155 -155
  244. package/pro/squads/design/tasks/f2-ingest-base-components.md +148 -148
  245. package/pro/squads/design/tasks/f2-qa-base-components.md +98 -98
  246. package/pro/squads/design/tasks/f3-derive-components.md +145 -145
  247. package/pro/squads/design/tasks/f3-qa-derived-components.md +101 -101
  248. package/pro/squads/design/tasks/focus-order-audit.md +450 -450
  249. package/pro/squads/design/tasks/sb-brownfield-migrate.md +367 -367
  250. package/pro/squads/design/tasks/sb-brownfield-scan.md +318 -318
  251. package/pro/squads/design/tasks/sb-configure.md +230 -230
  252. package/pro/squads/design/tasks/sb-expand-shadcn.md +213 -213
  253. package/pro/squads/design/tasks/sb-generate-all-stories.md +288 -288
  254. package/pro/squads/design/tasks/sb-install.md +152 -152
  255. package/pro/squads/design/tasks/sb-sync-workspace.md +239 -239
  256. package/pro/squads/design/tasks/sb-verify.md +203 -203
  257. package/pro/squads/design/tasks/tailwind-upgrade.md +117 -117
  258. package/pro/squads/design/tasks/token-usage-analytics.md +262 -262
  259. package/pro/squads/design/tasks/ux-rewrite-sixth-grade.md +82 -82
  260. package/pro/squads/design/tasks/validate-design-fidelity.md +222 -222
  261. package/pro/squads/design/templates/agent-template.yaml +46 -46
  262. package/pro/squads/design/templates/clone-mind-template.md +352 -352
  263. package/pro/squads/design/templates/component-prompt-injection-tmpl.md +236 -236
  264. package/pro/squads/design/templates/component-visual-spec-tmpl.md +378 -378
  265. package/pro/squads/design/templates/critical-eye-cycle-report-tmpl.md +165 -165
  266. package/pro/squads/design/templates/design-fidelity-report-tmpl.md +155 -155
  267. package/pro/squads/design/templates/ds-ai-component-metadata-schema-tmpl.json +138 -138
  268. package/pro/squads/design/templates/ds-artifact-analysis.md +70 -70
  269. package/pro/squads/design/templates/ds-health-report-tmpl.md +236 -236
  270. package/pro/squads/design/templates/ds-migration-strategy-tmpl.md +524 -524
  271. package/pro/squads/design/templates/ds-state-persistence-tmpl.yaml +194 -194
  272. package/pro/squads/design/templates/ds-tokens-schema-tmpl.yaml +139 -139
  273. package/pro/squads/design/templates/migration-strategy-tmpl.md +524 -524
  274. package/pro/squads/design/templates/reading-design-tokens.css +26 -26
  275. package/pro/squads/design/templates/state-persistence-tmpl.yaml +219 -219
  276. package/pro/squads/design/templates/tokens-schema-tmpl.yaml +305 -305
  277. package/pro/squads/design/workflows/agentic-readiness.yaml +83 -83
  278. package/pro/squads/design/workflows/audit-only.yaml +198 -198
  279. package/pro/squads/design/workflows/brownfield-complete.yaml +257 -257
  280. package/pro/squads/design/workflows/critical-eye.yaml +184 -184
  281. package/pro/squads/design/workflows/dtcg-tokens-governance.yaml +64 -64
  282. package/pro/squads/design/workflows/foundations-pipeline.yaml +192 -192
  283. package/pro/squads/design/workflows/greenfield-new.yaml +192 -192
  284. package/pro/squads/design/workflows/motion-quality.yaml +65 -65
  285. package/pro/squads/design/workflows/self-healing-workflow.yaml +237 -237
  286. package/pro/squads/design/workflows/storybook-brownfield-migration.yaml +400 -400
  287. package/pro/squads/design/workflows/storybook-full-setup.yaml +280 -280
  288. package/pro/squads/mmos-squad/minds/alex_hormozi/artifacts/ARQUITETURA_COGNITIVA_DE_ALEX_HORMOZI_EXTRA/303/207/303/203O_COMPLETA.md +215 -0
  289. package/pro/squads/mmos-squad/minds/alex_hormozi/artifacts/A_Rotina_de_Alta_Performance_de_Alex_Hormozi_Arquitetura,_Motiva/303/247/303/265es_e_Replica/303/247/303/243o.md +309 -0
  290. package/pro/squads/mmos-squad/minds/alex_hormozi/artifacts/O_sistema_completo_de_cria/303/247/303/243o_de_conte/303/272do_de_Alex_Hormozi.md +416 -0
  291. package/pro/squads/mmos-squad/minds/alex_hormozi/artifacts/Processo_Cria/303/247/303/243o_Conte/303/272do_Hormozi.md +0 -0
  292. package/pro/squads/mmos-squad/minds/brad_frost/.backup/2026-01-13/artifacts/DECIS/303/225ES_ESTRAT/303/211GICAS_DE_DESIGN_SYSTEMS_(2022_2025).md +1038 -0
  293. package/pro/squads/mmos-squad/minds/brad_frost/.backup/2026-01-13/artifacts/FRAMEWORK_COMPLETO_DE_IMPLEMENTA/303/207/303/203O_ATOMIC_DESIGN.md +797 -0
  294. package/pro/squads/mmos-squad/minds/brad_frost/.backup/2026-01-13/artifacts/O_Cemit/303/251rio_de_Design_Systems.md +447 -0
  295. package/pro/squads/mmos-squad/minds/brad_frost/.backup/2026-01-13/artifacts/PRINC/303/215PIOS_DE_RACIOC/303/215NIO.md +190 -0
  296. package/pro/squads/mmos-squad/minds/brad_frost/artifacts/DECIS/303/225ES_ESTRAT/303/211GICAS_DE_DESIGN_SYSTEMS_(2022_2025).md +1038 -0
  297. package/pro/squads/mmos-squad/minds/brad_frost/artifacts/FRAMEWORK_COMPLETO_DE_IMPLEMENTA/303/207/303/203O_ATOMIC_DESIGN.md +797 -0
  298. package/pro/squads/mmos-squad/minds/brad_frost/artifacts/O_Cemit/303/251rio_de_Design_Systems.md +447 -0
  299. package/pro/squads/mmos-squad/minds/brad_frost/artifacts/PRINC/303/215PIOS_DE_RACIOC/303/215NIO.md +190 -0
  300. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/AN/303/201LISE_PSICOM/303/211TRICA_PROFUNDA_ELON_MUSK.md +291 -0
  301. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/ASSINATURA_LINGU/303/215STICA_ELON_MUSK.md +485 -0
  302. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/A_Arquitetura_Mental_de_Elon_Musk_Uma_An/303/241lise_Sistem/303/241tica_dos_Frameworks_de_Pensamento.md +907 -0
  303. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/Dossi/303/252_Estrat/303/251gico_A_Arquitetura_Psicol/303/263gica_de_Elon_Musk.md +252 -0
  304. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/Os_Padr/303/265es_de_Leitura_de_Elon_Musk_e_Sua_Influ/303/252ncia_Sistem/303/241tica.md +287 -0
  305. package/pro/squads/mmos-squad/minds/elon_musk/artifacts/Uma_an/303/241lise_psicol/303/263gica_abrangente.md +187 -0
  306. package/pro/squads/mmos-squad/minds/eugene_schwartz/artifacts/AN/303/201LISE_PSICOM/303/211TRICA_PROFUNDA_EUGENE_M._SCHWARTZ.md +790 -0
  307. package/pro/squads/mmos-squad/minds/eugene_schwartz/artifacts/An/303/241lise_Completa_Eugene_Schwartz_Arquitetura_Cognitiva_DEEP.md +210 -0
  308. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/5H_EXTRA/303/207/303/203O_COGNITIVA_COMPLETA_PEDRO_VAL/303/211RIO_LOPEZ.md +226 -0
  309. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/AN/303/201LISE_COMPARATIVA_REVISADA_PEDRO_VAL/303/211RIO_LOPEZ.md +246 -0
  310. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/AN/303/201LISE_LINGU/303/215STICA_CARIOCA_PEDRO_VAL/303/211RIO_LOPEZ.md +274 -0
  311. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/AN/303/201LISE_PSICOM/303/211TRICA_DEFINITIVA_PEDRO_VAL/303/211RIO_LOPEZ.md +821 -0
  312. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/AN/303/201LISE_PSICOM/303/211TRICA_PROFUNDA_PEDRO_VAL/303/211RIO.md +1844 -0
  313. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/C/303/201LCULO_DE_RARIDADE_ESTAT/303/215STICA_PEDRO_VAL/303/211RIO_LOPEZ.md +154 -0
  314. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/EXTRA/303/207/303/203O_PEDRO_VAL/303/211RIO.md +237 -0
  315. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/MAPEAMENTO_LINGU/303/215STICO_PROFUNDO.md +161 -0
  316. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/META_AXIOMAS_DE_PEDRO_VAL/303/211RIO.md +256 -0
  317. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/SISTEMA_IMUNOL/303/223GICO_COGNITIVO_PEDRO_VAL/303/211RIO_LOPEZ.md +586 -0
  318. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/SISTEMA_IMUNOL/303/223GICO_COGNITIVO_V2_/342/200/224_CLONE_IA.md +452 -0
  319. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/TABELA_COMPARATIVA_AN/303/201LISE_COMPLETA_DOS_CLONES_IA.md +102 -0
  320. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/WHATSAPP_PADR/303/225ES_LINGU/303/215STICOS_PEDRO_VAL/303/211RIO_LOPEZ.md +286 -0
  321. package/pro/squads/mmos-squad/minds/pedro_valerio/sources/artifacts_v1.6/heur/303/255sticas_de_decis/303/243o_e_algoritmos_mentais_/303/272nicos.md +268 -0
  322. package/pro/squads/mmos-squad/minds/ray_kurzweil/sources/books/PROTOCOLO_COMPLETO_DE_INTERROGA/303/207/303/203O_-_NAVAL_RAVIKANT.md +3624 -0
  323. package/pro/squads/mmos-squad/minds/steve_jobs/artifacts/FRAMEWORK_COMPLETO_DE_IMPLEMENTA/303/207/303/203O_JOBS.md +488 -0
  324. package/pro/squads/mmos-squad/minds/steve_jobs/artifacts/Framework_Cabe/303/247a_Steve.md +257 -0
  325. package/pro/squads/mmos-squad/minds/steve_jobs/artifacts/Relat/303/263rio_Abrangente_sobre_Steve_Jobs_para_Cria/303/247/303/243o_de_Clone_de_IA.md +370 -0
  326. package/pro/squads/mmos-squad/minds/steve_jobs/artifacts/Steve_Jobs_An/303/241lise_Psicol/303/263gica_Profunda_e_Valida/303/247/303/243o_Comportamental.md +65 -0
  327. package/pro/squads/squad-creator-pro/HEADLINE.md +3 -3
  328. package/pro/squads/squad-creator-pro/agents/oalanicolas.md +438 -438
  329. package/pro/squads/squad-creator-pro/agents/squad-chief.md +1651 -1651
  330. package/pro/squads/squad-creator-pro/agents/thiago_finch.md +976 -976
  331. package/pro/squads/squad-creator-pro/assessments/axioma-assessment-wf-create-squad.yaml +325 -325
  332. package/pro/squads/squad-creator-pro/checklists/create-agent-checklist.md +184 -184
  333. package/pro/squads/squad-creator-pro/checklists/create-squad-checklist.md +219 -219
  334. package/pro/squads/squad-creator-pro/checklists/create-workflow-checklist.md +224 -224
  335. package/pro/squads/squad-creator-pro/checklists/mental-model-integration-checklist.md +95 -95
  336. package/pro/squads/squad-creator-pro/checklists/squad-overview-checklist.md +393 -393
  337. package/pro/squads/squad-creator-pro/config/model-routing.yaml +693 -693
  338. package/pro/squads/squad-creator-pro/config/scoring-rubric.yaml +199 -199
  339. package/pro/squads/squad-creator-pro/config.yaml +35 -35
  340. package/pro/squads/squad-creator-pro/data/internal-infrastructure-library.yaml +99 -99
  341. package/pro/squads/squad-creator-pro/data/mental-model-task-matrix.yaml +692 -692
  342. package/pro/squads/squad-creator-pro/docs/ADR-001-model-tier-qualification.md +344 -344
  343. package/pro/squads/squad-creator-pro/docs/AGENT-COLLABORATION.md +609 -609
  344. package/pro/squads/squad-creator-pro/docs/MIGRATION-PLAN-AGENT-CONFORMITY.md +861 -861
  345. package/pro/squads/squad-creator-pro/docs/MODEL-TIER-QUALIFICATION.md +337 -337
  346. package/pro/squads/squad-creator-pro/docs/optimize-v4-proposal.md +354 -354
  347. package/pro/squads/squad-creator-pro/docs/task-optimization-framework.md +229 -229
  348. package/pro/squads/squad-creator-pro/minds/oalanicolas/heuristics/AN_KE_010.md +240 -240
  349. package/pro/squads/squad-creator-pro/protocols/ai-first-governance.md +63 -63
  350. package/pro/squads/squad-creator-pro/scripts/assess-sources.sh +443 -443
  351. package/pro/squads/squad-creator-pro/scripts/clone-review.sh +394 -394
  352. package/pro/squads/squad-creator-pro/scripts/create-agent-preflight.py +243 -243
  353. package/pro/squads/squad-creator-pro/scripts/cross-provider/compare-results.js +281 -281
  354. package/pro/squads/squad-creator-pro/scripts/cross-provider/cross-provider-runner.js +462 -462
  355. package/pro/squads/squad-creator-pro/scripts/fidelity-score.sh +519 -519
  356. package/pro/squads/squad-creator-pro/scripts/generate-squad-guide.js +558 -558
  357. package/pro/squads/squad-creator-pro/scripts/lib/config-loader.js +151 -151
  358. package/pro/squads/squad-creator-pro/scripts/model-tier-validator.cjs +369 -369
  359. package/pro/squads/squad-creator-pro/scripts/model-usage-logger.cjs +245 -245
  360. package/pro/squads/squad-creator-pro/scripts/modernization-score.sh +308 -308
  361. package/pro/squads/squad-creator-pro/scripts/scaffold-squad.cjs +281 -281
  362. package/pro/squads/squad-creator-pro/scripts/security_scanner.py +378 -378
  363. package/pro/squads/squad-creator-pro/scripts/squad-context-loader.cjs +205 -205
  364. package/pro/squads/squad-creator-pro/scripts/squad-state-manager.cjs +451 -451
  365. package/pro/squads/squad-creator-pro/scripts/squad-workflow-runner.cjs +471 -471
  366. package/pro/squads/squad-creator-pro/scripts/squad_utils.py +261 -261
  367. package/pro/squads/squad-creator-pro/scripts/tests/run_bash_tests.sh +29 -29
  368. package/pro/squads/squad-creator-pro/scripts/tests/test_assess_sources.sh +216 -216
  369. package/pro/squads/squad-creator-pro/scripts/tests/test_clone_review.sh +239 -239
  370. package/pro/squads/squad-creator-pro/scripts/tests/test_coherence_validator.py +212 -212
  371. package/pro/squads/squad-creator-pro/scripts/tests/test_fidelity_score.sh +298 -298
  372. package/pro/squads/squad-creator-pro/scripts/tests/test_modernization_score.sh +211 -211
  373. package/pro/squads/squad-creator-pro/scripts/tests/test_security_scanner.py +354 -354
  374. package/pro/squads/squad-creator-pro/scripts/tests/test_validate_clone.sh +252 -252
  375. package/pro/squads/squad-creator-pro/squad.yaml +36 -36
  376. package/pro/squads/squad-creator-pro/tasks/an-compare-outputs.md +354 -354
  377. package/pro/squads/squad-creator-pro/tasks/create-squad.md +933 -933
  378. package/pro/squads/squad-creator-pro/tasks/detect-squad-context.md +81 -81
  379. package/pro/squads/squad-creator-pro/tasks/lookup-model.md +78 -78
  380. package/pro/squads/squad-creator-pro/tasks/next-squad.md +487 -487
  381. package/pro/squads/squad-creator-pro/tasks/optimize-workflow.md +851 -851
  382. package/pro/squads/squad-creator-pro/tasks/parallel-discovery.md +58 -58
  383. package/pro/squads/squad-creator-pro/tasks/pv-axioma-assessment-wf-clone-mind.yaml +256 -256
  384. package/pro/squads/squad-creator-pro/tasks/qualify-task.md +265 -265
  385. package/pro/squads/squad-creator-pro/tasks/reexecute-squad-phase.md +64 -64
  386. package/pro/squads/squad-creator-pro/tasks/smoke-test-model-routing.md +167 -167
  387. package/pro/squads/squad-creator-pro/tasks/squad-overview.md +683 -683
  388. package/pro/squads/squad-creator-pro/tasks/validate-final-artifacts.md +80 -80
  389. package/pro/squads/squad-creator-pro/templates/orchestrator-tmpl.md +74 -74
  390. package/pro/squads/squad-creator-pro/test-cases/BATCH-PROGRESS.md +268 -268
  391. package/pro/squads/squad-creator-pro/test-cases/QUALIFICATION-DASHBOARD.yaml +13 -13
  392. package/pro/squads/squad-creator-pro/test-cases/_template.yaml +147 -147
  393. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/ASSESSMENT-SUMMARY.md +275 -275
  394. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/ASSESSMENT_SUMMARY.md +140 -140
  395. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/CHECKPOINT_MATRIX.md +202 -202
  396. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/EXECUTION-REPORT.md +413 -413
  397. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/EXECUTION_NOTES.md +358 -358
  398. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/README-v2.2.2.md +299 -299
  399. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/README.md +320 -320
  400. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/TEST-REPORT-v2.1.md +351 -351
  401. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/VERIFICATION-CHECKLIST.txt +247 -247
  402. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/formal-qualification-report.yaml +389 -389
  403. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/haiku-output.yaml +366 -366
  404. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/haiku-v2.1-output.yaml +452 -452
  405. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/haiku-v2.2.1-output.yaml +281 -281
  406. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/haiku-v2.2.2-output.yaml +332 -332
  407. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/opus-baseline.yaml +517 -517
  408. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/qualification-report.yaml +213 -213
  409. package/pro/squads/squad-creator-pro/test-cases/an-assess-sources/test-case.yaml +69 -69
  410. package/pro/squads/squad-creator-pro/test-cases/an-clone-review/haiku-round-1.yaml +213 -213
  411. package/pro/squads/squad-creator-pro/test-cases/an-clone-review/opus-baseline.yaml +566 -566
  412. package/pro/squads/squad-creator-pro/test-cases/an-clone-review/qualification-report.yaml +82 -82
  413. package/pro/squads/squad-creator-pro/test-cases/an-design-clone/test-case.yaml +102 -102
  414. package/pro/squads/squad-creator-pro/test-cases/an-extract-dna/test-case.yaml +105 -105
  415. package/pro/squads/squad-creator-pro/test-cases/an-fidelity-score/haiku-round-1.yaml +262 -262
  416. package/pro/squads/squad-creator-pro/test-cases/an-fidelity-score/opus-baseline.yaml +266 -266
  417. package/pro/squads/squad-creator-pro/test-cases/an-fidelity-score/qualification-report.yaml +94 -94
  418. package/pro/squads/squad-creator-pro/test-cases/an-validate-clone/haiku-round-1.yaml +282 -282
  419. package/pro/squads/squad-creator-pro/test-cases/an-validate-clone/opus-baseline.yaml +470 -470
  420. package/pro/squads/squad-creator-pro/test-cases/an-validate-clone/qualification-report.yaml +106 -106
  421. package/pro/squads/squad-creator-pro/test-cases/collect-sources/test-case.yaml +105 -105
  422. package/pro/squads/squad-creator-pro/test-cases/create-task/test-case.yaml +104 -104
  423. package/pro/squads/squad-creator-pro/test-cases/cross-provider/DASHBOARD.yaml +11 -11
  424. package/pro/squads/squad-creator-pro/test-cases/pv-audit/test-case.yaml +106 -106
  425. package/pro/squads/squad-creator-pro/test-cases/pv-axioma-assessment/haiku-output.yaml +209 -209
  426. package/pro/squads/squad-creator-pro/test-cases/pv-axioma-assessment/opus-baseline.yaml +96 -96
  427. package/pro/squads/squad-creator-pro/test-cases/pv-axioma-assessment/sonnet-output.yaml +30 -30
  428. package/pro/squads/squad-creator-pro/test-cases/pv-axioma-assessment/test-case.yaml +129 -129
  429. package/pro/squads/squad-creator-pro/test-cases/pv-modernization-score/comparison-round-1.yaml +242 -242
  430. package/pro/squads/squad-creator-pro/test-cases/pv-modernization-score/haiku-round-1.yaml +393 -393
  431. package/pro/squads/squad-creator-pro/test-cases/pv-modernization-score/opus-baseline.yaml +488 -488
  432. package/pro/squads/squad-creator-pro/test-cases/pv-modernization-score/qualification-report.yaml +74 -74
  433. package/pro/squads/squad-creator-pro/test-cases/qa-after-creation/haiku-round-1.yaml +292 -292
  434. package/pro/squads/squad-creator-pro/test-cases/qa-after-creation/opus-baseline.yaml +603 -603
  435. package/pro/squads/squad-creator-pro/test-cases/qa-after-creation/qualification-report.yaml +97 -97
  436. package/pro/squads/squad-creator-pro/test-cases/smoke-test-model-routing/test-case.yaml +100 -100
  437. package/pro/squads/squad-creator-pro/test-cases/upgrade-squad/test-case.yaml +106 -106
  438. package/pro/squads/squad-creator-pro/test-cases/validate-squad/comparison-round-1.yaml +223 -223
  439. package/pro/squads/squad-creator-pro/test-cases/validate-squad/haiku-round-1-MINE.yaml +36 -36
  440. package/pro/squads/squad-creator-pro/test-cases/validate-squad/haiku-round-1.yaml +193 -193
  441. package/pro/squads/squad-creator-pro/test-cases/validate-squad/haiku-round-2.yaml +303 -303
  442. package/pro/squads/squad-creator-pro/test-cases/validate-squad/haiku-round-3-v4-task.yaml +149 -149
  443. package/pro/squads/squad-creator-pro/test-cases/validate-squad/opus-baseline.yaml +529 -529
  444. package/pro/squads/squad-creator-pro/test-cases/validate-squad/opus-round-3-v4-task.yaml +132 -132
  445. package/pro/squads/squad-creator-pro/test-cases/validate-squad/qualification-report.yaml +104 -104
  446. package/pro/squads/squad-creator-pro/test-cases/wf-clone-mind/haiku-output-v2-calibrated.yaml +200 -200
  447. package/pro/squads/squad-creator-pro/test-cases/wf-clone-mind/haiku-output.yaml +183 -183
  448. package/pro/squads/squad-creator-pro/test-cases/wf-clone-mind/opus-baseline.yaml +112 -112
  449. package/pro/squads/squad-creator-pro/workflows/create-squad.yaml +348 -348
  450. package/pro/squads/squad-creator-pro/workflows/modules/module-discovery.yaml +16 -16
  451. package/pro/squads/squad-creator-pro/workflows/modules/module-integration.yaml +16 -16
  452. package/pro/squads/squad-creator-pro/workflows/modules/module-quality-gates.yaml +15 -15
  453. package/pro/squads/squad-creator-pro/workflows/wf-brownfield-upgrade-squad.yaml +46 -46
  454. package/pro/squads/squad-creator-pro/workflows/wf-context-aware-create-squad.yaml +47 -47
  455. package/pro/squads/squad-creator-pro/workflows/wf-create-squad.yaml +1619 -1619
  456. package/pro/squads/squad-creator-pro/workflows/wf-cross-provider-qualification.yaml +711 -711
  457. package/pro/squads/squad-creator-pro/workflows/wf-model-tier-qualification.yaml +800 -800
  458. package/pro/squads/squad-creator-pro/workflows/wf-optimize-squad.yaml +684 -684
  459. package/scripts/check-markdown-links.py +352 -352
  460. package/scripts/dashboard-parallel-dev.sh +0 -0
  461. package/scripts/dashboard-parallel-phase3.sh +0 -0
  462. package/scripts/dashboard-parallel-phase4.sh +0 -0
  463. package/scripts/install-monitor-hooks.sh +0 -0
  464. package/.claude/hooks/code-intel-pretool.cjs +0 -107
  465. package/docs/guides/aios-workflows/README.md +0 -247
  466. package/docs/guides/aios-workflows/bob-orchestrator-workflow.md +0 -1536
  467. package/scripts/glue/README.md +0 -355
  468. package/scripts/glue/compose-agent-prompt.cjs +0 -362
@@ -1,806 +1,806 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Design Artifact Dissector
4
- * @module design/scripts/dissect-artifact
5
- * @version 1.0.0
6
- *
7
- * Pixel-level design extraction using Playwright.
8
- * Downloads HTML, extracts ALL CSS, maps complete DOM tree,
9
- * captures screenshots, and generates comprehensive design tokens.
10
- *
11
- * Usage:
12
- * node dissect-artifact.js <url|path> [options]
13
- *
14
- * Options:
15
- * --name, -n Artifact name (required, e.g. "landing-page")
16
- * --output, -o Output directory (default: outputs/design-system/scans/{name})
17
- * --viewport, -v Viewport: widthxheight (default: 1440x900)
18
- * --mobile Also capture mobile viewport (375x812)
19
- * --full-page Capture full-page screenshot (default: true)
20
- * --timeout, -t Navigation timeout in seconds (default: 30)
21
- * --help, -h Show help
22
- *
23
- * Output structure:
24
- * {output}/
25
- * ├── source.html # Raw HTML source
26
- * ├── screenshot-desktop.png # Full-page desktop screenshot
27
- * ├── screenshot-mobile.png # Full-page mobile screenshot (if --mobile)
28
- * ├── stylesheets/ # All external CSS files downloaded
29
- * ├── dom-tree.json # Complete DOM tree with computed styles
30
- * ├── extracted-css.json # All CSS rules organized by type
31
- * ├── tokens.yaml # Auto-generated design tokens
32
- * ├── components.json # Detected component patterns
33
- * └── manifest.json # Scan metadata and summary
34
- */
35
-
36
- const { chromium } = require('playwright');
37
- const fs = require('fs');
38
- const path = require('path');
39
-
40
- // ---------------------------------------------------------------------------
41
- // Args
42
- // ---------------------------------------------------------------------------
43
-
44
- function parseArgs(args) {
45
- const parsed = {
46
- target: null,
47
- name: null,
48
- output: null,
49
- viewport: { width: 1440, height: 900 },
50
- mobile: false,
51
- fullPage: true,
52
- timeout: 30,
53
- help: false,
54
- };
55
-
56
- for (let i = 0; i < args.length; i++) {
57
- const arg = args[i];
58
- if (arg === '--help' || arg === '-h') {
59
- parsed.help = true;
60
- } else if (arg === '--name' || arg === '-n') {
61
- parsed.name = args[++i];
62
- } else if (arg === '--output' || arg === '-o') {
63
- parsed.output = args[++i];
64
- } else if (arg === '--viewport' || arg === '-v') {
65
- const [w, h] = (args[++i] || '1440x900').split('x').map(Number);
66
- parsed.viewport = { width: w || 1440, height: h || 900 };
67
- } else if (arg === '--mobile') {
68
- parsed.mobile = true;
69
- } else if (arg === '--no-full-page') {
70
- parsed.fullPage = false;
71
- } else if (arg === '--timeout' || arg === '-t') {
72
- parsed.timeout = parseInt(args[++i]) || 30;
73
- } else if (!arg.startsWith('-') && !parsed.target) {
74
- parsed.target = arg;
75
- }
76
- }
77
-
78
- return parsed;
79
- }
80
-
81
- function showHelp() {
82
- console.log(`
83
- Design Artifact Dissector v1.0.0
84
-
85
- Usage:
86
- node dissect-artifact.js <url|path> --name <artifact-name> [options]
87
-
88
- Arguments:
89
- url|path URL or local file path to dissect
90
-
91
- Options:
92
- --name, -n Artifact name (required, e.g. "landing-page")
93
- --output, -o Output directory (default: outputs/design-system/scans/{name})
94
- --viewport, -v Viewport: WxH (default: 1440x900)
95
- --mobile Also capture mobile viewport (375x812)
96
- --no-full-page Only capture visible viewport
97
- --timeout, -t Navigation timeout in seconds (default: 30)
98
- --help, -h Show this help
99
-
100
- Examples:
101
- node dissect-artifact.js https://stripe.com --name stripe-home
102
- node dissect-artifact.js ./mockup.html --name dashboard-v2 --mobile
103
- node dissect-artifact.js https://linear.app --name linear-landing -v 1920x1080
104
- `);
105
- }
106
-
107
- // ---------------------------------------------------------------------------
108
- // DOM Extraction (runs in browser context)
109
- // ---------------------------------------------------------------------------
110
-
111
- /**
112
- * Extracts complete design data from the page.
113
- * This function runs inside the browser via page.evaluate().
114
- */
115
- function extractDesignData() {
116
- const result = {
117
- stylesheets: [],
118
- inlineStyles: [],
119
- cssRules: {
120
- colors: new Map(),
121
- typography: new Map(),
122
- spacing: new Map(),
123
- borders: new Map(),
124
- shadows: new Map(),
125
- gradients: [],
126
- animations: [],
127
- transitions: [],
128
- mediaQueries: [],
129
- customProperties: new Map(),
130
- gridLayouts: [],
131
- flexLayouts: [],
132
- },
133
- domTree: null,
134
- components: [],
135
- summary: {},
136
- };
137
-
138
- // ---- 1. Extract all CSS custom properties (CSS variables) ----
139
- const rootStyles = getComputedStyle(document.documentElement);
140
- for (let i = 0; i < rootStyles.length; i++) {
141
- const prop = rootStyles[i];
142
- if (prop.startsWith('--')) {
143
- result.cssRules.customProperties.set(prop, rootStyles.getPropertyValue(prop).trim());
144
- }
145
- }
146
-
147
- // ---- 2. Extract all stylesheet rules ----
148
- for (const sheet of document.styleSheets) {
149
- const sheetData = {
150
- href: sheet.href || '(embedded)',
151
- rules: [],
152
- };
153
-
154
- try {
155
- for (const rule of sheet.cssRules) {
156
- sheetData.rules.push({
157
- type: rule.type,
158
- selector: rule.selectorText || null,
159
- cssText: rule.cssText,
160
- media: rule.media ? Array.from(rule.media) : null,
161
- });
162
-
163
- // Collect media queries
164
- if (rule.type === CSSRule.MEDIA_RULE) {
165
- result.cssRules.mediaQueries.push({
166
- condition: rule.conditionText || rule.media.mediaText,
167
- ruleCount: rule.cssRules.length,
168
- rules: Array.from(rule.cssRules).map(r => ({
169
- selector: r.selectorText,
170
- cssText: r.cssText,
171
- })),
172
- });
173
- }
174
-
175
- // Collect animations
176
- if (rule.type === CSSRule.KEYFRAMES_RULE) {
177
- result.cssRules.animations.push({
178
- name: rule.name,
179
- cssText: rule.cssText,
180
- });
181
- }
182
- }
183
- } catch (e) {
184
- // Cross-origin stylesheets can't be read
185
- sheetData.error = 'Cross-origin: unable to read rules';
186
- }
187
-
188
- result.stylesheets.push(sheetData);
189
- }
190
-
191
- // ---- 3. Walk the DOM tree ----
192
- const STYLE_PROPS = [
193
- // Colors
194
- 'color', 'background-color', 'background-image', 'background',
195
- 'border-color', 'border-top-color', 'border-right-color',
196
- 'border-bottom-color', 'border-left-color', 'outline-color',
197
- // Typography
198
- 'font-family', 'font-size', 'font-weight', 'font-style',
199
- 'line-height', 'letter-spacing', 'text-align', 'text-decoration',
200
- 'text-transform', 'word-spacing', 'white-space',
201
- // Spacing
202
- 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
203
- 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
204
- // Layout
205
- 'display', 'position', 'top', 'right', 'bottom', 'left',
206
- 'width', 'height', 'min-width', 'min-height', 'max-width', 'max-height',
207
- 'overflow', 'overflow-x', 'overflow-y', 'z-index',
208
- // Flex
209
- 'flex-direction', 'flex-wrap', 'justify-content', 'align-items',
210
- 'align-content', 'gap', 'row-gap', 'column-gap',
211
- 'flex-grow', 'flex-shrink', 'flex-basis', 'order',
212
- // Grid
213
- 'grid-template-columns', 'grid-template-rows', 'grid-template-areas',
214
- 'grid-column', 'grid-row', 'grid-gap',
215
- // Border
216
- 'border-width', 'border-style', 'border-radius',
217
- 'border-top-left-radius', 'border-top-right-radius',
218
- 'border-bottom-left-radius', 'border-bottom-right-radius',
219
- // Shadow
220
- 'box-shadow', 'text-shadow',
221
- // Transform
222
- 'transform', 'opacity',
223
- // Transition/Animation
224
- 'transition', 'animation',
225
- // Other
226
- 'cursor', 'pointer-events', 'user-select', 'box-sizing',
227
- 'object-fit', 'object-position', 'aspect-ratio',
228
- 'backdrop-filter', 'filter', 'mix-blend-mode',
229
- 'clip-path', 'mask',
230
- ];
231
-
232
- let nodeCount = 0;
233
- const MAX_NODES = 5000;
234
-
235
- function walkDOM(element, depth = 0) {
236
- if (nodeCount >= MAX_NODES) return null;
237
- nodeCount++;
238
-
239
- const computed = getComputedStyle(element);
240
- const rect = element.getBoundingClientRect();
241
-
242
- // Extract only non-default / meaningful computed styles
243
- const styles = {};
244
- for (const prop of STYLE_PROPS) {
245
- const val = computed.getPropertyValue(prop).trim();
246
- if (val && val !== 'none' && val !== 'normal' && val !== 'auto' && val !== '0px' && val !== 'rgba(0, 0, 0, 0)') {
247
- styles[prop] = val;
248
- }
249
- }
250
-
251
- // Collect unique values
252
- if (styles['color']) result.cssRules.colors.set(styles['color'], (result.cssRules.colors.get(styles['color']) || 0) + 1);
253
- if (styles['background-color'] && styles['background-color'] !== 'rgba(0, 0, 0, 0)') {
254
- result.cssRules.colors.set(styles['background-color'], (result.cssRules.colors.get(styles['background-color']) || 0) + 1);
255
- }
256
- if (styles['background-image'] && styles['background-image'].includes('gradient')) {
257
- result.cssRules.gradients.push(styles['background-image']);
258
- }
259
- if (styles['font-family']) {
260
- const key = `${styles['font-size']}/${styles['font-weight']}/${styles['font-family']}`;
261
- result.cssRules.typography.set(key, (result.cssRules.typography.get(key) || 0) + 1);
262
- }
263
- if (styles['box-shadow']) result.cssRules.shadows.set(styles['box-shadow'], (result.cssRules.shadows.get(styles['box-shadow']) || 0) + 1);
264
- if (styles['transition']) result.cssRules.transitions.push(styles['transition']);
265
- if (styles['display'] === 'grid') {
266
- result.cssRules.gridLayouts.push({
267
- columns: styles['grid-template-columns'],
268
- rows: styles['grid-template-rows'],
269
- gap: styles['gap'] || styles['grid-gap'],
270
- });
271
- }
272
- if (styles['display'] === 'flex') {
273
- result.cssRules.flexLayouts.push({
274
- direction: styles['flex-direction'],
275
- wrap: styles['flex-wrap'],
276
- justify: styles['justify-content'],
277
- align: styles['align-items'],
278
- gap: styles['gap'],
279
- });
280
- }
281
-
282
- // Spacing values
283
- ['margin-top', 'margin-bottom', 'padding-top', 'padding-bottom', 'gap'].forEach(prop => {
284
- if (styles[prop] && styles[prop] !== '0px') {
285
- result.cssRules.spacing.set(styles[prop], (result.cssRules.spacing.get(styles[prop]) || 0) + 1);
286
- }
287
- });
288
-
289
- // Border values
290
- if (styles['border-width'] && styles['border-width'] !== '0px') {
291
- const key = `${styles['border-width']} ${styles['border-style']} ${styles['border-color']}`;
292
- result.cssRules.borders.set(key, (result.cssRules.borders.get(key) || 0) + 1);
293
- }
294
-
295
- const node = {
296
- tag: element.tagName.toLowerCase(),
297
- id: element.id || undefined,
298
- classes: element.className && typeof element.className === 'string'
299
- ? element.className.split(/\s+/).filter(Boolean)
300
- : [],
301
- rect: {
302
- x: Math.round(rect.x),
303
- y: Math.round(rect.y),
304
- width: Math.round(rect.width),
305
- height: Math.round(rect.height),
306
- },
307
- styles,
308
- attributes: {},
309
- text: null,
310
- children: [],
311
- };
312
-
313
- // Capture key attributes
314
- for (const attr of ['href', 'src', 'alt', 'role', 'aria-label', 'data-testid', 'type', 'placeholder']) {
315
- if (element.hasAttribute(attr)) {
316
- node.attributes[attr] = element.getAttribute(attr);
317
- }
318
- }
319
-
320
- // Inline styles
321
- if (element.style.cssText) {
322
- node.inlineStyle = element.style.cssText;
323
- result.inlineStyles.push({
324
- selector: `${node.tag}${node.id ? '#' + node.id : ''}${node.classes.length ? '.' + node.classes[0] : ''}`,
325
- cssText: element.style.cssText,
326
- });
327
- }
328
-
329
- // Text content (direct text only, not children)
330
- const directText = Array.from(element.childNodes)
331
- .filter(n => n.nodeType === Node.TEXT_NODE)
332
- .map(n => n.textContent.trim())
333
- .filter(Boolean)
334
- .join(' ');
335
- if (directText) node.text = directText.substring(0, 200);
336
-
337
- // Recurse children (elements only)
338
- for (const child of element.children) {
339
- if (['script', 'style', 'noscript', 'svg', 'path'].includes(child.tagName.toLowerCase())) continue;
340
- const childNode = walkDOM(child, depth + 1);
341
- if (childNode) node.children.push(childNode);
342
- }
343
-
344
- return node;
345
- }
346
-
347
- result.domTree = walkDOM(document.body);
348
- result.summary.nodeCount = nodeCount;
349
-
350
- // ---- 4. Detect component patterns ----
351
- const componentSelectors = [
352
- { pattern: 'nav, [role="navigation"]', type: 'navigation' },
353
- { pattern: 'header, [role="banner"]', type: 'header' },
354
- { pattern: 'footer, [role="contentinfo"]', type: 'footer' },
355
- { pattern: 'main, [role="main"]', type: 'main-content' },
356
- { pattern: 'aside, [role="complementary"]', type: 'sidebar' },
357
- { pattern: 'form', type: 'form' },
358
- { pattern: 'button, [role="button"], input[type="submit"]', type: 'button' },
359
- { pattern: 'a.btn, a.button, a.cta, a[class*="btn"], a[class*="button"]', type: 'cta-link' },
360
- { pattern: 'input, textarea, select', type: 'form-input' },
361
- { pattern: '[class*="card"], [class*="Card"]', type: 'card' },
362
- { pattern: '[class*="modal"], [class*="Modal"], [role="dialog"]', type: 'modal' },
363
- { pattern: '[class*="hero"], [class*="Hero"]', type: 'hero' },
364
- { pattern: '[class*="dropdown"], [class*="Dropdown"], [class*="menu"]', type: 'dropdown' },
365
- { pattern: '[class*="tab"], [role="tablist"]', type: 'tabs' },
366
- { pattern: '[class*="accordion"]', type: 'accordion' },
367
- { pattern: '[class*="toast"], [class*="notification"], [class*="alert"]', type: 'notification' },
368
- { pattern: '[class*="badge"], [class*="tag"], [class*="chip"]', type: 'badge' },
369
- { pattern: '[class*="avatar"]', type: 'avatar' },
370
- { pattern: '[class*="tooltip"]', type: 'tooltip' },
371
- { pattern: 'img, picture, [class*="image"], [class*="Image"]', type: 'image' },
372
- { pattern: 'video, [class*="video"]', type: 'video' },
373
- { pattern: '[class*="slider"], [class*="carousel"], [class*="swiper"]', type: 'carousel' },
374
- { pattern: '[class*="grid"], [class*="Grid"]', type: 'grid-layout' },
375
- { pattern: 'table, [class*="table"]', type: 'table' },
376
- { pattern: '[class*="breadcrumb"]', type: 'breadcrumb' },
377
- { pattern: '[class*="pagination"]', type: 'pagination' },
378
- { pattern: '[class*="progress"]', type: 'progress' },
379
- { pattern: '[class*="skeleton"], [class*="loading"]', type: 'skeleton' },
380
- ];
381
-
382
- for (const { pattern, type } of componentSelectors) {
383
- try {
384
- const elements = document.querySelectorAll(pattern);
385
- if (elements.length > 0) {
386
- const samples = Array.from(elements).slice(0, 3).map(el => {
387
- const r = el.getBoundingClientRect();
388
- const cs = getComputedStyle(el);
389
- return {
390
- tag: el.tagName.toLowerCase(),
391
- classes: el.className && typeof el.className === 'string' ? el.className.split(/\s+/).filter(Boolean).slice(0, 5) : [],
392
- rect: { x: Math.round(r.x), y: Math.round(r.y), width: Math.round(r.width), height: Math.round(r.height) },
393
- styles: {
394
- display: cs.display,
395
- background: cs.backgroundColor,
396
- color: cs.color,
397
- fontSize: cs.fontSize,
398
- fontWeight: cs.fontWeight,
399
- padding: `${cs.paddingTop} ${cs.paddingRight} ${cs.paddingBottom} ${cs.paddingLeft}`,
400
- borderRadius: cs.borderRadius,
401
- boxShadow: cs.boxShadow !== 'none' ? cs.boxShadow : undefined,
402
- },
403
- };
404
- });
405
-
406
- result.components.push({
407
- type,
408
- count: elements.length,
409
- samples,
410
- });
411
- }
412
- } catch (e) {
413
- // Invalid selector, skip
414
- }
415
- }
416
-
417
- // ---- 5. Convert Maps to objects for serialization ----
418
- const mapToSorted = (map) => {
419
- const entries = Array.from(map.entries());
420
- entries.sort((a, b) => b[1] - a[1]);
421
- return entries.map(([value, count]) => ({ value, count }));
422
- };
423
-
424
- return {
425
- stylesheets: result.stylesheets,
426
- inlineStyles: result.inlineStyles,
427
- cssRules: {
428
- colors: mapToSorted(result.cssRules.colors),
429
- typography: mapToSorted(result.cssRules.typography),
430
- spacing: mapToSorted(result.cssRules.spacing),
431
- borders: mapToSorted(result.cssRules.borders),
432
- shadows: mapToSorted(result.cssRules.shadows),
433
- gradients: [...new Set(result.cssRules.gradients)],
434
- animations: result.cssRules.animations,
435
- transitions: [...new Set(result.cssRules.transitions)].slice(0, 50),
436
- mediaQueries: result.cssRules.mediaQueries,
437
- customProperties: Object.fromEntries(result.cssRules.customProperties),
438
- gridLayouts: result.cssRules.gridLayouts.slice(0, 20),
439
- flexLayouts: result.cssRules.flexLayouts.slice(0, 50),
440
- },
441
- domTree: result.domTree,
442
- components: result.components,
443
- summary: result.summary,
444
- };
445
- }
446
-
447
- // ---------------------------------------------------------------------------
448
- // Token Generation
449
- // ---------------------------------------------------------------------------
450
-
451
- function generateTokensYaml(data, meta) {
452
- const lines = [];
453
- lines.push(`# Design Tokens - ${meta.name}`);
454
- lines.push(`# Extracted by dissect-artifact.js v1.0.0`);
455
- lines.push(`# Source: ${meta.target}`);
456
- lines.push(`# Date: ${meta.timestamp}`);
457
- lines.push('');
458
- lines.push('metadata:');
459
- lines.push(` version: "1.0.0"`);
460
- lines.push(` source: "${meta.target}"`);
461
- lines.push(` generated_at: "${meta.timestamp}"`);
462
- lines.push(` node_count: ${data.summary.nodeCount}`);
463
- lines.push('');
464
-
465
- // Colors
466
- lines.push('colors:');
467
- if (data.cssRules.colors.length === 0) {
468
- lines.push(' # No colors extracted');
469
- }
470
- for (const { value, count } of data.cssRules.colors.slice(0, 40)) {
471
- const safeName = value.replace(/[^a-zA-Z0-9]/g, '_').replace(/_+/g, '_');
472
- lines.push(` "${safeName}":`);
473
- lines.push(` value: "${value}"`);
474
- lines.push(` occurrences: ${count}`);
475
- }
476
- lines.push('');
477
-
478
- // Typography
479
- lines.push('typography:');
480
- if (data.cssRules.typography.length === 0) {
481
- lines.push(' # No typography extracted');
482
- }
483
- for (const { value, count } of data.cssRules.typography.slice(0, 20)) {
484
- const [size, weight, family] = value.split('/');
485
- const name = `${size}_${weight}`.replace(/[^a-zA-Z0-9]/g, '_');
486
- lines.push(` "${name}":`);
487
- lines.push(` font-size: "${size}"`);
488
- lines.push(` font-weight: "${weight}"`);
489
- lines.push(` font-family: "${family}"`);
490
- lines.push(` occurrences: ${count}`);
491
- }
492
- lines.push('');
493
-
494
- // Spacing
495
- lines.push('spacing:');
496
- if (data.cssRules.spacing.length === 0) {
497
- lines.push(' # No spacing extracted');
498
- }
499
- for (const { value, count } of data.cssRules.spacing.slice(0, 20)) {
500
- const name = value.replace(/[^a-zA-Z0-9]/g, '_');
501
- lines.push(` "${name}":`);
502
- lines.push(` value: "${value}"`);
503
- lines.push(` occurrences: ${count}`);
504
- }
505
- lines.push('');
506
-
507
- // Shadows
508
- if (data.cssRules.shadows.length > 0) {
509
- lines.push('shadows:');
510
- data.cssRules.shadows.slice(0, 10).forEach(({ value, count }, i) => {
511
- lines.push(` shadow_${i + 1}:`);
512
- lines.push(` value: "${value.replace(/"/g, '\\"')}"`);
513
- lines.push(` occurrences: ${count}`);
514
- });
515
- lines.push('');
516
- }
517
-
518
- // Borders
519
- if (data.cssRules.borders.length > 0) {
520
- lines.push('borders:');
521
- data.cssRules.borders.slice(0, 10).forEach(({ value, count }, i) => {
522
- lines.push(` border_${i + 1}:`);
523
- lines.push(` value: "${value.replace(/"/g, '\\"')}"`);
524
- lines.push(` occurrences: ${count}`);
525
- });
526
- lines.push('');
527
- }
528
-
529
- // Gradients
530
- if (data.cssRules.gradients.length > 0) {
531
- lines.push('gradients:');
532
- data.cssRules.gradients.slice(0, 10).forEach((val, i) => {
533
- lines.push(` gradient_${i + 1}: "${val.replace(/"/g, '\\"')}"`);
534
- });
535
- lines.push('');
536
- }
537
-
538
- // CSS Custom Properties
539
- const customProps = Object.entries(data.cssRules.customProperties);
540
- if (customProps.length > 0) {
541
- lines.push('custom_properties:');
542
- for (const [prop, val] of customProps.slice(0, 50)) {
543
- lines.push(` "${prop}": "${val.replace(/"/g, '\\"')}"`);
544
- }
545
- lines.push('');
546
- }
547
-
548
- return lines.join('\n');
549
- }
550
-
551
- // ---------------------------------------------------------------------------
552
- // External stylesheet downloader
553
- // ---------------------------------------------------------------------------
554
-
555
- async function downloadStylesheets(page, outputDir) {
556
- const stylesheetDir = path.join(outputDir, 'stylesheets');
557
- fs.mkdirSync(stylesheetDir, { recursive: true });
558
-
559
- const stylesheetUrls = await page.evaluate(() => {
560
- return Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
561
- .map(link => link.href)
562
- .filter(href => href && href.startsWith('http'));
563
- });
564
-
565
- const downloaded = [];
566
- for (const url of stylesheetUrls) {
567
- try {
568
- const response = await page.request.get(url);
569
- const body = await response.text();
570
- const filename = url.split('/').pop().split('?')[0] || 'stylesheet.css';
571
- const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '_').substring(0, 80);
572
- const filePath = path.join(stylesheetDir, safeName);
573
- fs.writeFileSync(filePath, body);
574
- downloaded.push({ url, file: safeName, size: body.length });
575
- console.error(` Downloaded: ${safeName} (${body.length} bytes)`);
576
- } catch (e) {
577
- downloaded.push({ url, error: e.message });
578
- console.error(` Failed: ${url} (${e.message})`);
579
- }
580
- }
581
-
582
- // Also extract embedded <style> tags
583
- const embeddedStyles = await page.evaluate(() => {
584
- return Array.from(document.querySelectorAll('style'))
585
- .map((el, i) => ({ index: i, cssText: el.textContent }))
586
- .filter(s => s.cssText.trim().length > 0);
587
- });
588
-
589
- for (const { index, cssText } of embeddedStyles) {
590
- const filePath = path.join(stylesheetDir, `embedded-${index}.css`);
591
- fs.writeFileSync(filePath, cssText);
592
- downloaded.push({ embedded: true, file: `embedded-${index}.css`, size: cssText.length });
593
- console.error(` Extracted: embedded-${index}.css (${cssText.length} bytes)`);
594
- }
595
-
596
- return downloaded;
597
- }
598
-
599
- // ---------------------------------------------------------------------------
600
- // Main
601
- // ---------------------------------------------------------------------------
602
-
603
- async function main() {
604
- const args = parseArgs(process.argv.slice(2));
605
-
606
- if (args.help) {
607
- showHelp();
608
- process.exit(0);
609
- }
610
-
611
- if (!args.target) {
612
- console.error('Error: URL or file path is required');
613
- console.error('Usage: node dissect-artifact.js <url|path> --name <name>');
614
- process.exit(1);
615
- }
616
-
617
- if (!args.name) {
618
- console.error('Error: --name is required');
619
- console.error('Usage: node dissect-artifact.js <url|path> --name <name>');
620
- process.exit(1);
621
- }
622
-
623
- // Determine if target is URL or file
624
- const isUrl = args.target.startsWith('http://') || args.target.startsWith('https://');
625
- const target = isUrl ? args.target : `file://${path.resolve(args.target)}`;
626
-
627
- // Output directory
628
- const projectRoot = path.resolve(__dirname, '../../..');
629
- const outputDir = args.output || path.join(projectRoot, 'outputs', 'design-system', 'scans', args.name);
630
- fs.mkdirSync(outputDir, { recursive: true });
631
- fs.mkdirSync(path.join(outputDir, 'stylesheets'), { recursive: true });
632
-
633
- const timestamp = new Date().toISOString();
634
- console.error(`\n=== Design Artifact Dissector v1.0.0 ===`);
635
- console.error(`Target: ${args.target}`);
636
- console.error(`Name: ${args.name}`);
637
- console.error(`Output: ${outputDir}`);
638
- console.error(`Viewport: ${args.viewport.width}x${args.viewport.height}`);
639
- console.error('');
640
-
641
- let browser;
642
- try {
643
- // Launch browser
644
- console.error('1/7 Launching browser...');
645
- browser = await chromium.launch({ headless: true });
646
- const context = await browser.newContext({
647
- viewport: args.viewport,
648
- deviceScaleFactor: 2, // Retina
649
- userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
650
- });
651
- const page = await context.newPage();
652
-
653
- // Navigate
654
- console.error('2/7 Loading page...');
655
- await page.goto(target, {
656
- waitUntil: 'networkidle',
657
- timeout: args.timeout * 1000,
658
- });
659
-
660
- // Wait extra for JS rendering
661
- await page.waitForTimeout(2000);
662
-
663
- // Save raw HTML
664
- console.error('3/7 Saving HTML source...');
665
- const html = await page.content();
666
- fs.writeFileSync(path.join(outputDir, 'source.html'), html);
667
- console.error(` Saved: source.html (${html.length} bytes)`);
668
-
669
- // Download all stylesheets
670
- console.error('4/7 Downloading stylesheets...');
671
- const stylesheetManifest = await downloadStylesheets(page, outputDir);
672
-
673
- // Take screenshots
674
- console.error('5/7 Capturing screenshots...');
675
- await page.screenshot({
676
- path: path.join(outputDir, 'screenshot-desktop.png'),
677
- fullPage: args.fullPage,
678
- type: 'png',
679
- });
680
- console.error(' Saved: screenshot-desktop.png');
681
-
682
- if (args.mobile) {
683
- await page.setViewportSize({ width: 375, height: 812 });
684
- await page.waitForTimeout(1000);
685
- await page.screenshot({
686
- path: path.join(outputDir, 'screenshot-mobile.png'),
687
- fullPage: args.fullPage,
688
- type: 'png',
689
- });
690
- console.error(' Saved: screenshot-mobile.png');
691
-
692
- // Reset to desktop for extraction
693
- await page.setViewportSize(args.viewport);
694
- await page.waitForTimeout(500);
695
- }
696
-
697
- // Extract design data
698
- console.error('6/7 Extracting design data (DOM walk + computed styles)...');
699
- const designData = await page.evaluate(extractDesignData);
700
-
701
- // Save extracted data
702
- fs.writeFileSync(
703
- path.join(outputDir, 'dom-tree.json'),
704
- JSON.stringify(designData.domTree, null, 2)
705
- );
706
- console.error(` Saved: dom-tree.json (${designData.summary.nodeCount} nodes)`);
707
-
708
- fs.writeFileSync(
709
- path.join(outputDir, 'extracted-css.json'),
710
- JSON.stringify(designData.cssRules, null, 2)
711
- );
712
- console.error(` Saved: extracted-css.json`);
713
-
714
- fs.writeFileSync(
715
- path.join(outputDir, 'components.json'),
716
- JSON.stringify(designData.components, null, 2)
717
- );
718
- console.error(` Saved: components.json (${designData.components.length} component types)`);
719
-
720
- // Generate tokens
721
- console.error('7/7 Generating design tokens...');
722
- const tokensYaml = generateTokensYaml(designData, {
723
- name: args.name,
724
- target: args.target,
725
- timestamp,
726
- });
727
- fs.writeFileSync(path.join(outputDir, 'tokens.yaml'), tokensYaml);
728
- console.error(' Saved: tokens.yaml');
729
-
730
- // Generate manifest
731
- const manifest = {
732
- version: '1.0.0',
733
- name: args.name,
734
- source: args.target,
735
- timestamp,
736
- viewport: args.viewport,
737
- output: outputDir,
738
- files: {
739
- html: { file: 'source.html', size: html.length },
740
- screenshots: ['screenshot-desktop.png', ...(args.mobile ? ['screenshot-mobile.png'] : [])],
741
- stylesheets: stylesheetManifest,
742
- domTree: { file: 'dom-tree.json', nodeCount: designData.summary.nodeCount },
743
- extractedCss: 'extracted-css.json',
744
- components: { file: 'components.json', count: designData.components.length },
745
- tokens: 'tokens.yaml',
746
- },
747
- summary: {
748
- nodeCount: designData.summary.nodeCount,
749
- uniqueColors: designData.cssRules.colors.length,
750
- typographyVariants: designData.cssRules.typography.length,
751
- spacingValues: designData.cssRules.spacing.length,
752
- shadows: designData.cssRules.shadows.length,
753
- gradients: designData.cssRules.gradients.length,
754
- animations: designData.cssRules.animations.length,
755
- mediaQueries: designData.cssRules.mediaQueries.length,
756
- customProperties: Object.keys(designData.cssRules.customProperties).length,
757
- gridLayouts: designData.cssRules.gridLayouts.length,
758
- flexLayouts: designData.cssRules.flexLayouts.length,
759
- componentTypes: designData.components.length,
760
- totalComponents: designData.components.reduce((sum, c) => sum + c.count, 0),
761
- stylesheetCount: stylesheetManifest.length,
762
- inlineStyles: designData.inlineStyles.length,
763
- },
764
- };
765
-
766
- fs.writeFileSync(
767
- path.join(outputDir, 'manifest.json'),
768
- JSON.stringify(manifest, null, 2)
769
- );
770
-
771
- // ---- Print summary to stdout (for agent consumption) ----
772
- console.log(JSON.stringify(manifest, null, 2));
773
-
774
- console.error('\n=== Dissection Complete ===');
775
- console.error(`Output: ${outputDir}`);
776
- console.error('');
777
- console.error('Summary:');
778
- console.error(` Nodes scanned: ${manifest.summary.nodeCount}`);
779
- console.error(` Unique colors: ${manifest.summary.uniqueColors}`);
780
- console.error(` Typography: ${manifest.summary.typographyVariants} variants`);
781
- console.error(` Spacing values: ${manifest.summary.spacingValues}`);
782
- console.error(` Shadows: ${manifest.summary.shadows}`);
783
- console.error(` Gradients: ${manifest.summary.gradients}`);
784
- console.error(` Animations: ${manifest.summary.animations}`);
785
- console.error(` Media queries: ${manifest.summary.mediaQueries}`);
786
- console.error(` CSS variables: ${manifest.summary.customProperties}`);
787
- console.error(` Grid layouts: ${manifest.summary.gridLayouts}`);
788
- console.error(` Flex layouts: ${manifest.summary.flexLayouts}`);
789
- console.error(` Component types: ${manifest.summary.componentTypes}`);
790
- console.error(` Total components: ${manifest.summary.totalComponents}`);
791
- console.error(` Stylesheets: ${manifest.summary.stylesheetCount}`);
792
- console.error(` Inline styles: ${manifest.summary.inlineStyles}`);
793
-
794
- } catch (error) {
795
- console.error(`\nError: ${error.message}`);
796
- if (error.message.includes('Executable doesn\'t exist')) {
797
- console.error('\nPlaywright browsers not installed. Run:');
798
- console.error(' npx playwright install chromium');
799
- }
800
- process.exit(1);
801
- } finally {
802
- if (browser) await browser.close();
803
- }
804
- }
805
-
806
- main();
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Design Artifact Dissector
4
+ * @module design/scripts/dissect-artifact
5
+ * @version 1.0.0
6
+ *
7
+ * Pixel-level design extraction using Playwright.
8
+ * Downloads HTML, extracts ALL CSS, maps complete DOM tree,
9
+ * captures screenshots, and generates comprehensive design tokens.
10
+ *
11
+ * Usage:
12
+ * node dissect-artifact.js <url|path> [options]
13
+ *
14
+ * Options:
15
+ * --name, -n Artifact name (required, e.g. "landing-page")
16
+ * --output, -o Output directory (default: outputs/design-system/scans/{name})
17
+ * --viewport, -v Viewport: widthxheight (default: 1440x900)
18
+ * --mobile Also capture mobile viewport (375x812)
19
+ * --full-page Capture full-page screenshot (default: true)
20
+ * --timeout, -t Navigation timeout in seconds (default: 30)
21
+ * --help, -h Show help
22
+ *
23
+ * Output structure:
24
+ * {output}/
25
+ * ├── source.html # Raw HTML source
26
+ * ├── screenshot-desktop.png # Full-page desktop screenshot
27
+ * ├── screenshot-mobile.png # Full-page mobile screenshot (if --mobile)
28
+ * ├── stylesheets/ # All external CSS files downloaded
29
+ * ├── dom-tree.json # Complete DOM tree with computed styles
30
+ * ├── extracted-css.json # All CSS rules organized by type
31
+ * ├── tokens.yaml # Auto-generated design tokens
32
+ * ├── components.json # Detected component patterns
33
+ * └── manifest.json # Scan metadata and summary
34
+ */
35
+
36
+ const { chromium } = require('playwright');
37
+ const fs = require('fs');
38
+ const path = require('path');
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Args
42
+ // ---------------------------------------------------------------------------
43
+
44
+ function parseArgs(args) {
45
+ const parsed = {
46
+ target: null,
47
+ name: null,
48
+ output: null,
49
+ viewport: { width: 1440, height: 900 },
50
+ mobile: false,
51
+ fullPage: true,
52
+ timeout: 30,
53
+ help: false,
54
+ };
55
+
56
+ for (let i = 0; i < args.length; i++) {
57
+ const arg = args[i];
58
+ if (arg === '--help' || arg === '-h') {
59
+ parsed.help = true;
60
+ } else if (arg === '--name' || arg === '-n') {
61
+ parsed.name = args[++i];
62
+ } else if (arg === '--output' || arg === '-o') {
63
+ parsed.output = args[++i];
64
+ } else if (arg === '--viewport' || arg === '-v') {
65
+ const [w, h] = (args[++i] || '1440x900').split('x').map(Number);
66
+ parsed.viewport = { width: w || 1440, height: h || 900 };
67
+ } else if (arg === '--mobile') {
68
+ parsed.mobile = true;
69
+ } else if (arg === '--no-full-page') {
70
+ parsed.fullPage = false;
71
+ } else if (arg === '--timeout' || arg === '-t') {
72
+ parsed.timeout = parseInt(args[++i]) || 30;
73
+ } else if (!arg.startsWith('-') && !parsed.target) {
74
+ parsed.target = arg;
75
+ }
76
+ }
77
+
78
+ return parsed;
79
+ }
80
+
81
+ function showHelp() {
82
+ console.log(`
83
+ Design Artifact Dissector v1.0.0
84
+
85
+ Usage:
86
+ node dissect-artifact.js <url|path> --name <artifact-name> [options]
87
+
88
+ Arguments:
89
+ url|path URL or local file path to dissect
90
+
91
+ Options:
92
+ --name, -n Artifact name (required, e.g. "landing-page")
93
+ --output, -o Output directory (default: outputs/design-system/scans/{name})
94
+ --viewport, -v Viewport: WxH (default: 1440x900)
95
+ --mobile Also capture mobile viewport (375x812)
96
+ --no-full-page Only capture visible viewport
97
+ --timeout, -t Navigation timeout in seconds (default: 30)
98
+ --help, -h Show this help
99
+
100
+ Examples:
101
+ node dissect-artifact.js https://stripe.com --name stripe-home
102
+ node dissect-artifact.js ./mockup.html --name dashboard-v2 --mobile
103
+ node dissect-artifact.js https://linear.app --name linear-landing -v 1920x1080
104
+ `);
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // DOM Extraction (runs in browser context)
109
+ // ---------------------------------------------------------------------------
110
+
111
+ /**
112
+ * Extracts complete design data from the page.
113
+ * This function runs inside the browser via page.evaluate().
114
+ */
115
+ function extractDesignData() {
116
+ const result = {
117
+ stylesheets: [],
118
+ inlineStyles: [],
119
+ cssRules: {
120
+ colors: new Map(),
121
+ typography: new Map(),
122
+ spacing: new Map(),
123
+ borders: new Map(),
124
+ shadows: new Map(),
125
+ gradients: [],
126
+ animations: [],
127
+ transitions: [],
128
+ mediaQueries: [],
129
+ customProperties: new Map(),
130
+ gridLayouts: [],
131
+ flexLayouts: [],
132
+ },
133
+ domTree: null,
134
+ components: [],
135
+ summary: {},
136
+ };
137
+
138
+ // ---- 1. Extract all CSS custom properties (CSS variables) ----
139
+ const rootStyles = getComputedStyle(document.documentElement);
140
+ for (let i = 0; i < rootStyles.length; i++) {
141
+ const prop = rootStyles[i];
142
+ if (prop.startsWith('--')) {
143
+ result.cssRules.customProperties.set(prop, rootStyles.getPropertyValue(prop).trim());
144
+ }
145
+ }
146
+
147
+ // ---- 2. Extract all stylesheet rules ----
148
+ for (const sheet of document.styleSheets) {
149
+ const sheetData = {
150
+ href: sheet.href || '(embedded)',
151
+ rules: [],
152
+ };
153
+
154
+ try {
155
+ for (const rule of sheet.cssRules) {
156
+ sheetData.rules.push({
157
+ type: rule.type,
158
+ selector: rule.selectorText || null,
159
+ cssText: rule.cssText,
160
+ media: rule.media ? Array.from(rule.media) : null,
161
+ });
162
+
163
+ // Collect media queries
164
+ if (rule.type === CSSRule.MEDIA_RULE) {
165
+ result.cssRules.mediaQueries.push({
166
+ condition: rule.conditionText || rule.media.mediaText,
167
+ ruleCount: rule.cssRules.length,
168
+ rules: Array.from(rule.cssRules).map(r => ({
169
+ selector: r.selectorText,
170
+ cssText: r.cssText,
171
+ })),
172
+ });
173
+ }
174
+
175
+ // Collect animations
176
+ if (rule.type === CSSRule.KEYFRAMES_RULE) {
177
+ result.cssRules.animations.push({
178
+ name: rule.name,
179
+ cssText: rule.cssText,
180
+ });
181
+ }
182
+ }
183
+ } catch (e) {
184
+ // Cross-origin stylesheets can't be read
185
+ sheetData.error = 'Cross-origin: unable to read rules';
186
+ }
187
+
188
+ result.stylesheets.push(sheetData);
189
+ }
190
+
191
+ // ---- 3. Walk the DOM tree ----
192
+ const STYLE_PROPS = [
193
+ // Colors
194
+ 'color', 'background-color', 'background-image', 'background',
195
+ 'border-color', 'border-top-color', 'border-right-color',
196
+ 'border-bottom-color', 'border-left-color', 'outline-color',
197
+ // Typography
198
+ 'font-family', 'font-size', 'font-weight', 'font-style',
199
+ 'line-height', 'letter-spacing', 'text-align', 'text-decoration',
200
+ 'text-transform', 'word-spacing', 'white-space',
201
+ // Spacing
202
+ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
203
+ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
204
+ // Layout
205
+ 'display', 'position', 'top', 'right', 'bottom', 'left',
206
+ 'width', 'height', 'min-width', 'min-height', 'max-width', 'max-height',
207
+ 'overflow', 'overflow-x', 'overflow-y', 'z-index',
208
+ // Flex
209
+ 'flex-direction', 'flex-wrap', 'justify-content', 'align-items',
210
+ 'align-content', 'gap', 'row-gap', 'column-gap',
211
+ 'flex-grow', 'flex-shrink', 'flex-basis', 'order',
212
+ // Grid
213
+ 'grid-template-columns', 'grid-template-rows', 'grid-template-areas',
214
+ 'grid-column', 'grid-row', 'grid-gap',
215
+ // Border
216
+ 'border-width', 'border-style', 'border-radius',
217
+ 'border-top-left-radius', 'border-top-right-radius',
218
+ 'border-bottom-left-radius', 'border-bottom-right-radius',
219
+ // Shadow
220
+ 'box-shadow', 'text-shadow',
221
+ // Transform
222
+ 'transform', 'opacity',
223
+ // Transition/Animation
224
+ 'transition', 'animation',
225
+ // Other
226
+ 'cursor', 'pointer-events', 'user-select', 'box-sizing',
227
+ 'object-fit', 'object-position', 'aspect-ratio',
228
+ 'backdrop-filter', 'filter', 'mix-blend-mode',
229
+ 'clip-path', 'mask',
230
+ ];
231
+
232
+ let nodeCount = 0;
233
+ const MAX_NODES = 5000;
234
+
235
+ function walkDOM(element, depth = 0) {
236
+ if (nodeCount >= MAX_NODES) return null;
237
+ nodeCount++;
238
+
239
+ const computed = getComputedStyle(element);
240
+ const rect = element.getBoundingClientRect();
241
+
242
+ // Extract only non-default / meaningful computed styles
243
+ const styles = {};
244
+ for (const prop of STYLE_PROPS) {
245
+ const val = computed.getPropertyValue(prop).trim();
246
+ if (val && val !== 'none' && val !== 'normal' && val !== 'auto' && val !== '0px' && val !== 'rgba(0, 0, 0, 0)') {
247
+ styles[prop] = val;
248
+ }
249
+ }
250
+
251
+ // Collect unique values
252
+ if (styles['color']) result.cssRules.colors.set(styles['color'], (result.cssRules.colors.get(styles['color']) || 0) + 1);
253
+ if (styles['background-color'] && styles['background-color'] !== 'rgba(0, 0, 0, 0)') {
254
+ result.cssRules.colors.set(styles['background-color'], (result.cssRules.colors.get(styles['background-color']) || 0) + 1);
255
+ }
256
+ if (styles['background-image'] && styles['background-image'].includes('gradient')) {
257
+ result.cssRules.gradients.push(styles['background-image']);
258
+ }
259
+ if (styles['font-family']) {
260
+ const key = `${styles['font-size']}/${styles['font-weight']}/${styles['font-family']}`;
261
+ result.cssRules.typography.set(key, (result.cssRules.typography.get(key) || 0) + 1);
262
+ }
263
+ if (styles['box-shadow']) result.cssRules.shadows.set(styles['box-shadow'], (result.cssRules.shadows.get(styles['box-shadow']) || 0) + 1);
264
+ if (styles['transition']) result.cssRules.transitions.push(styles['transition']);
265
+ if (styles['display'] === 'grid') {
266
+ result.cssRules.gridLayouts.push({
267
+ columns: styles['grid-template-columns'],
268
+ rows: styles['grid-template-rows'],
269
+ gap: styles['gap'] || styles['grid-gap'],
270
+ });
271
+ }
272
+ if (styles['display'] === 'flex') {
273
+ result.cssRules.flexLayouts.push({
274
+ direction: styles['flex-direction'],
275
+ wrap: styles['flex-wrap'],
276
+ justify: styles['justify-content'],
277
+ align: styles['align-items'],
278
+ gap: styles['gap'],
279
+ });
280
+ }
281
+
282
+ // Spacing values
283
+ ['margin-top', 'margin-bottom', 'padding-top', 'padding-bottom', 'gap'].forEach(prop => {
284
+ if (styles[prop] && styles[prop] !== '0px') {
285
+ result.cssRules.spacing.set(styles[prop], (result.cssRules.spacing.get(styles[prop]) || 0) + 1);
286
+ }
287
+ });
288
+
289
+ // Border values
290
+ if (styles['border-width'] && styles['border-width'] !== '0px') {
291
+ const key = `${styles['border-width']} ${styles['border-style']} ${styles['border-color']}`;
292
+ result.cssRules.borders.set(key, (result.cssRules.borders.get(key) || 0) + 1);
293
+ }
294
+
295
+ const node = {
296
+ tag: element.tagName.toLowerCase(),
297
+ id: element.id || undefined,
298
+ classes: element.className && typeof element.className === 'string'
299
+ ? element.className.split(/\s+/).filter(Boolean)
300
+ : [],
301
+ rect: {
302
+ x: Math.round(rect.x),
303
+ y: Math.round(rect.y),
304
+ width: Math.round(rect.width),
305
+ height: Math.round(rect.height),
306
+ },
307
+ styles,
308
+ attributes: {},
309
+ text: null,
310
+ children: [],
311
+ };
312
+
313
+ // Capture key attributes
314
+ for (const attr of ['href', 'src', 'alt', 'role', 'aria-label', 'data-testid', 'type', 'placeholder']) {
315
+ if (element.hasAttribute(attr)) {
316
+ node.attributes[attr] = element.getAttribute(attr);
317
+ }
318
+ }
319
+
320
+ // Inline styles
321
+ if (element.style.cssText) {
322
+ node.inlineStyle = element.style.cssText;
323
+ result.inlineStyles.push({
324
+ selector: `${node.tag}${node.id ? '#' + node.id : ''}${node.classes.length ? '.' + node.classes[0] : ''}`,
325
+ cssText: element.style.cssText,
326
+ });
327
+ }
328
+
329
+ // Text content (direct text only, not children)
330
+ const directText = Array.from(element.childNodes)
331
+ .filter(n => n.nodeType === Node.TEXT_NODE)
332
+ .map(n => n.textContent.trim())
333
+ .filter(Boolean)
334
+ .join(' ');
335
+ if (directText) node.text = directText.substring(0, 200);
336
+
337
+ // Recurse children (elements only)
338
+ for (const child of element.children) {
339
+ if (['script', 'style', 'noscript', 'svg', 'path'].includes(child.tagName.toLowerCase())) continue;
340
+ const childNode = walkDOM(child, depth + 1);
341
+ if (childNode) node.children.push(childNode);
342
+ }
343
+
344
+ return node;
345
+ }
346
+
347
+ result.domTree = walkDOM(document.body);
348
+ result.summary.nodeCount = nodeCount;
349
+
350
+ // ---- 4. Detect component patterns ----
351
+ const componentSelectors = [
352
+ { pattern: 'nav, [role="navigation"]', type: 'navigation' },
353
+ { pattern: 'header, [role="banner"]', type: 'header' },
354
+ { pattern: 'footer, [role="contentinfo"]', type: 'footer' },
355
+ { pattern: 'main, [role="main"]', type: 'main-content' },
356
+ { pattern: 'aside, [role="complementary"]', type: 'sidebar' },
357
+ { pattern: 'form', type: 'form' },
358
+ { pattern: 'button, [role="button"], input[type="submit"]', type: 'button' },
359
+ { pattern: 'a.btn, a.button, a.cta, a[class*="btn"], a[class*="button"]', type: 'cta-link' },
360
+ { pattern: 'input, textarea, select', type: 'form-input' },
361
+ { pattern: '[class*="card"], [class*="Card"]', type: 'card' },
362
+ { pattern: '[class*="modal"], [class*="Modal"], [role="dialog"]', type: 'modal' },
363
+ { pattern: '[class*="hero"], [class*="Hero"]', type: 'hero' },
364
+ { pattern: '[class*="dropdown"], [class*="Dropdown"], [class*="menu"]', type: 'dropdown' },
365
+ { pattern: '[class*="tab"], [role="tablist"]', type: 'tabs' },
366
+ { pattern: '[class*="accordion"]', type: 'accordion' },
367
+ { pattern: '[class*="toast"], [class*="notification"], [class*="alert"]', type: 'notification' },
368
+ { pattern: '[class*="badge"], [class*="tag"], [class*="chip"]', type: 'badge' },
369
+ { pattern: '[class*="avatar"]', type: 'avatar' },
370
+ { pattern: '[class*="tooltip"]', type: 'tooltip' },
371
+ { pattern: 'img, picture, [class*="image"], [class*="Image"]', type: 'image' },
372
+ { pattern: 'video, [class*="video"]', type: 'video' },
373
+ { pattern: '[class*="slider"], [class*="carousel"], [class*="swiper"]', type: 'carousel' },
374
+ { pattern: '[class*="grid"], [class*="Grid"]', type: 'grid-layout' },
375
+ { pattern: 'table, [class*="table"]', type: 'table' },
376
+ { pattern: '[class*="breadcrumb"]', type: 'breadcrumb' },
377
+ { pattern: '[class*="pagination"]', type: 'pagination' },
378
+ { pattern: '[class*="progress"]', type: 'progress' },
379
+ { pattern: '[class*="skeleton"], [class*="loading"]', type: 'skeleton' },
380
+ ];
381
+
382
+ for (const { pattern, type } of componentSelectors) {
383
+ try {
384
+ const elements = document.querySelectorAll(pattern);
385
+ if (elements.length > 0) {
386
+ const samples = Array.from(elements).slice(0, 3).map(el => {
387
+ const r = el.getBoundingClientRect();
388
+ const cs = getComputedStyle(el);
389
+ return {
390
+ tag: el.tagName.toLowerCase(),
391
+ classes: el.className && typeof el.className === 'string' ? el.className.split(/\s+/).filter(Boolean).slice(0, 5) : [],
392
+ rect: { x: Math.round(r.x), y: Math.round(r.y), width: Math.round(r.width), height: Math.round(r.height) },
393
+ styles: {
394
+ display: cs.display,
395
+ background: cs.backgroundColor,
396
+ color: cs.color,
397
+ fontSize: cs.fontSize,
398
+ fontWeight: cs.fontWeight,
399
+ padding: `${cs.paddingTop} ${cs.paddingRight} ${cs.paddingBottom} ${cs.paddingLeft}`,
400
+ borderRadius: cs.borderRadius,
401
+ boxShadow: cs.boxShadow !== 'none' ? cs.boxShadow : undefined,
402
+ },
403
+ };
404
+ });
405
+
406
+ result.components.push({
407
+ type,
408
+ count: elements.length,
409
+ samples,
410
+ });
411
+ }
412
+ } catch (e) {
413
+ // Invalid selector, skip
414
+ }
415
+ }
416
+
417
+ // ---- 5. Convert Maps to objects for serialization ----
418
+ const mapToSorted = (map) => {
419
+ const entries = Array.from(map.entries());
420
+ entries.sort((a, b) => b[1] - a[1]);
421
+ return entries.map(([value, count]) => ({ value, count }));
422
+ };
423
+
424
+ return {
425
+ stylesheets: result.stylesheets,
426
+ inlineStyles: result.inlineStyles,
427
+ cssRules: {
428
+ colors: mapToSorted(result.cssRules.colors),
429
+ typography: mapToSorted(result.cssRules.typography),
430
+ spacing: mapToSorted(result.cssRules.spacing),
431
+ borders: mapToSorted(result.cssRules.borders),
432
+ shadows: mapToSorted(result.cssRules.shadows),
433
+ gradients: [...new Set(result.cssRules.gradients)],
434
+ animations: result.cssRules.animations,
435
+ transitions: [...new Set(result.cssRules.transitions)].slice(0, 50),
436
+ mediaQueries: result.cssRules.mediaQueries,
437
+ customProperties: Object.fromEntries(result.cssRules.customProperties),
438
+ gridLayouts: result.cssRules.gridLayouts.slice(0, 20),
439
+ flexLayouts: result.cssRules.flexLayouts.slice(0, 50),
440
+ },
441
+ domTree: result.domTree,
442
+ components: result.components,
443
+ summary: result.summary,
444
+ };
445
+ }
446
+
447
+ // ---------------------------------------------------------------------------
448
+ // Token Generation
449
+ // ---------------------------------------------------------------------------
450
+
451
+ function generateTokensYaml(data, meta) {
452
+ const lines = [];
453
+ lines.push(`# Design Tokens - ${meta.name}`);
454
+ lines.push(`# Extracted by dissect-artifact.js v1.0.0`);
455
+ lines.push(`# Source: ${meta.target}`);
456
+ lines.push(`# Date: ${meta.timestamp}`);
457
+ lines.push('');
458
+ lines.push('metadata:');
459
+ lines.push(` version: "1.0.0"`);
460
+ lines.push(` source: "${meta.target}"`);
461
+ lines.push(` generated_at: "${meta.timestamp}"`);
462
+ lines.push(` node_count: ${data.summary.nodeCount}`);
463
+ lines.push('');
464
+
465
+ // Colors
466
+ lines.push('colors:');
467
+ if (data.cssRules.colors.length === 0) {
468
+ lines.push(' # No colors extracted');
469
+ }
470
+ for (const { value, count } of data.cssRules.colors.slice(0, 40)) {
471
+ const safeName = value.replace(/[^a-zA-Z0-9]/g, '_').replace(/_+/g, '_');
472
+ lines.push(` "${safeName}":`);
473
+ lines.push(` value: "${value}"`);
474
+ lines.push(` occurrences: ${count}`);
475
+ }
476
+ lines.push('');
477
+
478
+ // Typography
479
+ lines.push('typography:');
480
+ if (data.cssRules.typography.length === 0) {
481
+ lines.push(' # No typography extracted');
482
+ }
483
+ for (const { value, count } of data.cssRules.typography.slice(0, 20)) {
484
+ const [size, weight, family] = value.split('/');
485
+ const name = `${size}_${weight}`.replace(/[^a-zA-Z0-9]/g, '_');
486
+ lines.push(` "${name}":`);
487
+ lines.push(` font-size: "${size}"`);
488
+ lines.push(` font-weight: "${weight}"`);
489
+ lines.push(` font-family: "${family}"`);
490
+ lines.push(` occurrences: ${count}`);
491
+ }
492
+ lines.push('');
493
+
494
+ // Spacing
495
+ lines.push('spacing:');
496
+ if (data.cssRules.spacing.length === 0) {
497
+ lines.push(' # No spacing extracted');
498
+ }
499
+ for (const { value, count } of data.cssRules.spacing.slice(0, 20)) {
500
+ const name = value.replace(/[^a-zA-Z0-9]/g, '_');
501
+ lines.push(` "${name}":`);
502
+ lines.push(` value: "${value}"`);
503
+ lines.push(` occurrences: ${count}`);
504
+ }
505
+ lines.push('');
506
+
507
+ // Shadows
508
+ if (data.cssRules.shadows.length > 0) {
509
+ lines.push('shadows:');
510
+ data.cssRules.shadows.slice(0, 10).forEach(({ value, count }, i) => {
511
+ lines.push(` shadow_${i + 1}:`);
512
+ lines.push(` value: "${value.replace(/"/g, '\\"')}"`);
513
+ lines.push(` occurrences: ${count}`);
514
+ });
515
+ lines.push('');
516
+ }
517
+
518
+ // Borders
519
+ if (data.cssRules.borders.length > 0) {
520
+ lines.push('borders:');
521
+ data.cssRules.borders.slice(0, 10).forEach(({ value, count }, i) => {
522
+ lines.push(` border_${i + 1}:`);
523
+ lines.push(` value: "${value.replace(/"/g, '\\"')}"`);
524
+ lines.push(` occurrences: ${count}`);
525
+ });
526
+ lines.push('');
527
+ }
528
+
529
+ // Gradients
530
+ if (data.cssRules.gradients.length > 0) {
531
+ lines.push('gradients:');
532
+ data.cssRules.gradients.slice(0, 10).forEach((val, i) => {
533
+ lines.push(` gradient_${i + 1}: "${val.replace(/"/g, '\\"')}"`);
534
+ });
535
+ lines.push('');
536
+ }
537
+
538
+ // CSS Custom Properties
539
+ const customProps = Object.entries(data.cssRules.customProperties);
540
+ if (customProps.length > 0) {
541
+ lines.push('custom_properties:');
542
+ for (const [prop, val] of customProps.slice(0, 50)) {
543
+ lines.push(` "${prop}": "${val.replace(/"/g, '\\"')}"`);
544
+ }
545
+ lines.push('');
546
+ }
547
+
548
+ return lines.join('\n');
549
+ }
550
+
551
+ // ---------------------------------------------------------------------------
552
+ // External stylesheet downloader
553
+ // ---------------------------------------------------------------------------
554
+
555
+ async function downloadStylesheets(page, outputDir) {
556
+ const stylesheetDir = path.join(outputDir, 'stylesheets');
557
+ fs.mkdirSync(stylesheetDir, { recursive: true });
558
+
559
+ const stylesheetUrls = await page.evaluate(() => {
560
+ return Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
561
+ .map(link => link.href)
562
+ .filter(href => href && href.startsWith('http'));
563
+ });
564
+
565
+ const downloaded = [];
566
+ for (const url of stylesheetUrls) {
567
+ try {
568
+ const response = await page.request.get(url);
569
+ const body = await response.text();
570
+ const filename = url.split('/').pop().split('?')[0] || 'stylesheet.css';
571
+ const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '_').substring(0, 80);
572
+ const filePath = path.join(stylesheetDir, safeName);
573
+ fs.writeFileSync(filePath, body);
574
+ downloaded.push({ url, file: safeName, size: body.length });
575
+ console.error(` Downloaded: ${safeName} (${body.length} bytes)`);
576
+ } catch (e) {
577
+ downloaded.push({ url, error: e.message });
578
+ console.error(` Failed: ${url} (${e.message})`);
579
+ }
580
+ }
581
+
582
+ // Also extract embedded <style> tags
583
+ const embeddedStyles = await page.evaluate(() => {
584
+ return Array.from(document.querySelectorAll('style'))
585
+ .map((el, i) => ({ index: i, cssText: el.textContent }))
586
+ .filter(s => s.cssText.trim().length > 0);
587
+ });
588
+
589
+ for (const { index, cssText } of embeddedStyles) {
590
+ const filePath = path.join(stylesheetDir, `embedded-${index}.css`);
591
+ fs.writeFileSync(filePath, cssText);
592
+ downloaded.push({ embedded: true, file: `embedded-${index}.css`, size: cssText.length });
593
+ console.error(` Extracted: embedded-${index}.css (${cssText.length} bytes)`);
594
+ }
595
+
596
+ return downloaded;
597
+ }
598
+
599
+ // ---------------------------------------------------------------------------
600
+ // Main
601
+ // ---------------------------------------------------------------------------
602
+
603
+ async function main() {
604
+ const args = parseArgs(process.argv.slice(2));
605
+
606
+ if (args.help) {
607
+ showHelp();
608
+ process.exit(0);
609
+ }
610
+
611
+ if (!args.target) {
612
+ console.error('Error: URL or file path is required');
613
+ console.error('Usage: node dissect-artifact.js <url|path> --name <name>');
614
+ process.exit(1);
615
+ }
616
+
617
+ if (!args.name) {
618
+ console.error('Error: --name is required');
619
+ console.error('Usage: node dissect-artifact.js <url|path> --name <name>');
620
+ process.exit(1);
621
+ }
622
+
623
+ // Determine if target is URL or file
624
+ const isUrl = args.target.startsWith('http://') || args.target.startsWith('https://');
625
+ const target = isUrl ? args.target : `file://${path.resolve(args.target)}`;
626
+
627
+ // Output directory
628
+ const projectRoot = path.resolve(__dirname, '../../..');
629
+ const outputDir = args.output || path.join(projectRoot, 'outputs', 'design-system', 'scans', args.name);
630
+ fs.mkdirSync(outputDir, { recursive: true });
631
+ fs.mkdirSync(path.join(outputDir, 'stylesheets'), { recursive: true });
632
+
633
+ const timestamp = new Date().toISOString();
634
+ console.error(`\n=== Design Artifact Dissector v1.0.0 ===`);
635
+ console.error(`Target: ${args.target}`);
636
+ console.error(`Name: ${args.name}`);
637
+ console.error(`Output: ${outputDir}`);
638
+ console.error(`Viewport: ${args.viewport.width}x${args.viewport.height}`);
639
+ console.error('');
640
+
641
+ let browser;
642
+ try {
643
+ // Launch browser
644
+ console.error('1/7 Launching browser...');
645
+ browser = await chromium.launch({ headless: true });
646
+ const context = await browser.newContext({
647
+ viewport: args.viewport,
648
+ deviceScaleFactor: 2, // Retina
649
+ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
650
+ });
651
+ const page = await context.newPage();
652
+
653
+ // Navigate
654
+ console.error('2/7 Loading page...');
655
+ await page.goto(target, {
656
+ waitUntil: 'networkidle',
657
+ timeout: args.timeout * 1000,
658
+ });
659
+
660
+ // Wait extra for JS rendering
661
+ await page.waitForTimeout(2000);
662
+
663
+ // Save raw HTML
664
+ console.error('3/7 Saving HTML source...');
665
+ const html = await page.content();
666
+ fs.writeFileSync(path.join(outputDir, 'source.html'), html);
667
+ console.error(` Saved: source.html (${html.length} bytes)`);
668
+
669
+ // Download all stylesheets
670
+ console.error('4/7 Downloading stylesheets...');
671
+ const stylesheetManifest = await downloadStylesheets(page, outputDir);
672
+
673
+ // Take screenshots
674
+ console.error('5/7 Capturing screenshots...');
675
+ await page.screenshot({
676
+ path: path.join(outputDir, 'screenshot-desktop.png'),
677
+ fullPage: args.fullPage,
678
+ type: 'png',
679
+ });
680
+ console.error(' Saved: screenshot-desktop.png');
681
+
682
+ if (args.mobile) {
683
+ await page.setViewportSize({ width: 375, height: 812 });
684
+ await page.waitForTimeout(1000);
685
+ await page.screenshot({
686
+ path: path.join(outputDir, 'screenshot-mobile.png'),
687
+ fullPage: args.fullPage,
688
+ type: 'png',
689
+ });
690
+ console.error(' Saved: screenshot-mobile.png');
691
+
692
+ // Reset to desktop for extraction
693
+ await page.setViewportSize(args.viewport);
694
+ await page.waitForTimeout(500);
695
+ }
696
+
697
+ // Extract design data
698
+ console.error('6/7 Extracting design data (DOM walk + computed styles)...');
699
+ const designData = await page.evaluate(extractDesignData);
700
+
701
+ // Save extracted data
702
+ fs.writeFileSync(
703
+ path.join(outputDir, 'dom-tree.json'),
704
+ JSON.stringify(designData.domTree, null, 2)
705
+ );
706
+ console.error(` Saved: dom-tree.json (${designData.summary.nodeCount} nodes)`);
707
+
708
+ fs.writeFileSync(
709
+ path.join(outputDir, 'extracted-css.json'),
710
+ JSON.stringify(designData.cssRules, null, 2)
711
+ );
712
+ console.error(` Saved: extracted-css.json`);
713
+
714
+ fs.writeFileSync(
715
+ path.join(outputDir, 'components.json'),
716
+ JSON.stringify(designData.components, null, 2)
717
+ );
718
+ console.error(` Saved: components.json (${designData.components.length} component types)`);
719
+
720
+ // Generate tokens
721
+ console.error('7/7 Generating design tokens...');
722
+ const tokensYaml = generateTokensYaml(designData, {
723
+ name: args.name,
724
+ target: args.target,
725
+ timestamp,
726
+ });
727
+ fs.writeFileSync(path.join(outputDir, 'tokens.yaml'), tokensYaml);
728
+ console.error(' Saved: tokens.yaml');
729
+
730
+ // Generate manifest
731
+ const manifest = {
732
+ version: '1.0.0',
733
+ name: args.name,
734
+ source: args.target,
735
+ timestamp,
736
+ viewport: args.viewport,
737
+ output: outputDir,
738
+ files: {
739
+ html: { file: 'source.html', size: html.length },
740
+ screenshots: ['screenshot-desktop.png', ...(args.mobile ? ['screenshot-mobile.png'] : [])],
741
+ stylesheets: stylesheetManifest,
742
+ domTree: { file: 'dom-tree.json', nodeCount: designData.summary.nodeCount },
743
+ extractedCss: 'extracted-css.json',
744
+ components: { file: 'components.json', count: designData.components.length },
745
+ tokens: 'tokens.yaml',
746
+ },
747
+ summary: {
748
+ nodeCount: designData.summary.nodeCount,
749
+ uniqueColors: designData.cssRules.colors.length,
750
+ typographyVariants: designData.cssRules.typography.length,
751
+ spacingValues: designData.cssRules.spacing.length,
752
+ shadows: designData.cssRules.shadows.length,
753
+ gradients: designData.cssRules.gradients.length,
754
+ animations: designData.cssRules.animations.length,
755
+ mediaQueries: designData.cssRules.mediaQueries.length,
756
+ customProperties: Object.keys(designData.cssRules.customProperties).length,
757
+ gridLayouts: designData.cssRules.gridLayouts.length,
758
+ flexLayouts: designData.cssRules.flexLayouts.length,
759
+ componentTypes: designData.components.length,
760
+ totalComponents: designData.components.reduce((sum, c) => sum + c.count, 0),
761
+ stylesheetCount: stylesheetManifest.length,
762
+ inlineStyles: designData.inlineStyles.length,
763
+ },
764
+ };
765
+
766
+ fs.writeFileSync(
767
+ path.join(outputDir, 'manifest.json'),
768
+ JSON.stringify(manifest, null, 2)
769
+ );
770
+
771
+ // ---- Print summary to stdout (for agent consumption) ----
772
+ console.log(JSON.stringify(manifest, null, 2));
773
+
774
+ console.error('\n=== Dissection Complete ===');
775
+ console.error(`Output: ${outputDir}`);
776
+ console.error('');
777
+ console.error('Summary:');
778
+ console.error(` Nodes scanned: ${manifest.summary.nodeCount}`);
779
+ console.error(` Unique colors: ${manifest.summary.uniqueColors}`);
780
+ console.error(` Typography: ${manifest.summary.typographyVariants} variants`);
781
+ console.error(` Spacing values: ${manifest.summary.spacingValues}`);
782
+ console.error(` Shadows: ${manifest.summary.shadows}`);
783
+ console.error(` Gradients: ${manifest.summary.gradients}`);
784
+ console.error(` Animations: ${manifest.summary.animations}`);
785
+ console.error(` Media queries: ${manifest.summary.mediaQueries}`);
786
+ console.error(` CSS variables: ${manifest.summary.customProperties}`);
787
+ console.error(` Grid layouts: ${manifest.summary.gridLayouts}`);
788
+ console.error(` Flex layouts: ${manifest.summary.flexLayouts}`);
789
+ console.error(` Component types: ${manifest.summary.componentTypes}`);
790
+ console.error(` Total components: ${manifest.summary.totalComponents}`);
791
+ console.error(` Stylesheets: ${manifest.summary.stylesheetCount}`);
792
+ console.error(` Inline styles: ${manifest.summary.inlineStyles}`);
793
+
794
+ } catch (error) {
795
+ console.error(`\nError: ${error.message}`);
796
+ if (error.message.includes('Executable doesn\'t exist')) {
797
+ console.error('\nPlaywright browsers not installed. Run:');
798
+ console.error(' npx playwright install chromium');
799
+ }
800
+ process.exit(1);
801
+ } finally {
802
+ if (browser) await browser.close();
803
+ }
804
+ }
805
+
806
+ main();