@bovinphang/frontend-craft 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +72 -1
  4. package/CHANGELOG.zh-CN.md +71 -1
  5. package/README.md +10 -6
  6. package/README.openclaw.md +100 -42
  7. package/README.openclaw.zh-CN.md +100 -42
  8. package/README.zh-CN.md +10 -6
  9. package/agents/fec-architect.md +70 -70
  10. package/agents/fec-code-reviewer.md +82 -82
  11. package/agents/fec-debugger.md +20 -20
  12. package/agents/fec-design-token-mapper.md +36 -36
  13. package/agents/fec-doc-updater.md +13 -13
  14. package/agents/fec-e2e-runner.md +45 -45
  15. package/agents/fec-figma-implementer.md +59 -59
  16. package/agents/fec-performance-optimizer.md +128 -128
  17. package/agents/fec-refactor-cleaner.md +14 -14
  18. package/agents/fec-security-reviewer.md +66 -67
  19. package/agents/fec-test-planner.md +27 -27
  20. package/agents/fec-typescript-reviewer.md +88 -88
  21. package/agents/fec-ui-checker.md +74 -74
  22. package/commands/fec-debug.md +19 -19
  23. package/commands/fec-doc-sync.md +11 -11
  24. package/commands/fec-init.md +37 -38
  25. package/commands/fec-plan.md +58 -58
  26. package/commands/fec-refactor-clean.md +11 -11
  27. package/commands/fec-review.md +41 -41
  28. package/commands/fec-scaffold.md +41 -41
  29. package/commands/fec-tdd.md +13 -13
  30. package/dist/bin/frontend-craft.js +29 -27
  31. package/docs/example-prompts.md +84 -69
  32. package/docs/ja-JP/README.md +56 -52
  33. package/docs/ko-KR/README.md +45 -41
  34. package/docs/project-structure.md +19 -7
  35. package/docs/superpowers/plans/2026-05-29-fec-debug.md +491 -0
  36. package/docs/superpowers/specs/2026-05-29-fec-debug-design.md +340 -0
  37. package/docs/zh-CN/example-prompts.md +84 -69
  38. package/docs/zh-CN/project-structure.md +14 -5
  39. package/docs/zh-TW/README.md +33 -29
  40. package/localized/zh-CN/agents/fec-architect.md +125 -0
  41. package/localized/zh-CN/agents/fec-code-reviewer.md +152 -0
  42. package/localized/zh-CN/agents/fec-debugger.md +44 -0
  43. package/localized/zh-CN/agents/fec-design-token-mapper.md +75 -0
  44. package/localized/zh-CN/agents/fec-doc-updater.md +30 -0
  45. package/localized/zh-CN/agents/fec-e2e-runner.md +107 -0
  46. package/localized/zh-CN/agents/fec-figma-implementer.md +104 -0
  47. package/localized/zh-CN/agents/fec-performance-optimizer.md +293 -0
  48. package/localized/zh-CN/agents/fec-refactor-cleaner.md +32 -0
  49. package/localized/zh-CN/agents/fec-security-reviewer.md +116 -0
  50. package/localized/zh-CN/agents/fec-test-planner.md +50 -0
  51. package/localized/zh-CN/agents/fec-typescript-reviewer.md +142 -0
  52. package/localized/zh-CN/agents/fec-ui-checker.md +120 -0
  53. package/localized/zh-CN/commands/fec-debug.md +30 -0
  54. package/localized/zh-CN/commands/fec-doc-sync.md +19 -0
  55. package/localized/zh-CN/commands/fec-init.md +70 -0
  56. package/localized/zh-CN/commands/fec-plan.md +94 -0
  57. package/localized/zh-CN/commands/fec-refactor-clean.md +19 -0
  58. package/localized/zh-CN/commands/fec-review.md +66 -0
  59. package/localized/zh-CN/commands/fec-scaffold.md +205 -0
  60. package/localized/zh-CN/commands/fec-tdd.md +21 -0
  61. package/localized/zh-CN/skills/TEMPLATE.md +155 -0
  62. package/localized/zh-CN/skills/eval_queries.json +1013 -0
  63. package/localized/zh-CN/skills/fec-accessibility-check/SKILL.md +39 -0
  64. package/localized/zh-CN/skills/fec-accessibility-check/references/report-template.md +23 -0
  65. package/localized/zh-CN/skills/fec-accessibility-check/references/screen-reader-testing.md +33 -0
  66. package/localized/zh-CN/skills/fec-alchemy/SKILL.md +74 -0
  67. package/localized/zh-CN/skills/fec-alchemy/assets/absorption-plan-template.md +47 -0
  68. package/localized/zh-CN/skills/fec-alchemy/assets/intake-template.md +55 -0
  69. package/localized/zh-CN/skills/fec-alchemy/assets/review-checklist.md +31 -0
  70. package/localized/zh-CN/skills/fec-alchemy/references/methodology.md +94 -0
  71. package/localized/zh-CN/skills/fec-alchemy/references/originality-and-licensing.md +57 -0
  72. package/localized/zh-CN/skills/fec-api-integration/SKILL.md +78 -0
  73. package/localized/zh-CN/skills/fec-api-integration/references/integration-patterns.md +80 -0
  74. package/localized/zh-CN/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
  75. package/localized/zh-CN/skills/fec-browser-storage/SKILL.md +34 -0
  76. package/localized/zh-CN/skills/fec-browser-storage/references/storage-patterns.md +65 -0
  77. package/localized/zh-CN/skills/fec-canvas-threejs/SKILL.md +66 -0
  78. package/localized/zh-CN/skills/fec-canvas-threejs/references/rendering-patterns.md +67 -0
  79. package/localized/zh-CN/skills/fec-canvas-threejs/references/shader-webgl-patterns.md +67 -0
  80. package/localized/zh-CN/skills/fec-code-review/SKILL.md +143 -0
  81. package/localized/zh-CN/skills/fec-code-review/references/report-template.md +29 -0
  82. package/localized/zh-CN/skills/fec-component-testing/SKILL.md +119 -0
  83. package/localized/zh-CN/skills/fec-data-fetching/SKILL.md +62 -0
  84. package/localized/zh-CN/skills/fec-data-fetching/references/query-patterns.md +103 -0
  85. package/localized/zh-CN/skills/fec-debug-framework/SKILL.md +157 -0
  86. package/localized/zh-CN/skills/fec-debug-framework/references/report-template.md +58 -0
  87. package/localized/zh-CN/skills/fec-dependency-upgrade/SKILL.md +34 -0
  88. package/localized/zh-CN/skills/fec-dependency-upgrade/references/dependency-upgrade-workflow.md +56 -0
  89. package/localized/zh-CN/skills/fec-doc-sync/SKILL.md +39 -0
  90. package/localized/zh-CN/skills/fec-drawio-studio/SKILL.md +73 -0
  91. package/localized/zh-CN/skills/fec-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
  92. package/localized/zh-CN/skills/fec-drawio-studio/data/brand-icons.json +878 -0
  93. package/localized/zh-CN/skills/fec-drawio-studio/data/shape-index.json +83570 -0
  94. package/localized/zh-CN/skills/fec-drawio-studio/references/data-residency.md +27 -0
  95. package/localized/zh-CN/skills/fec-drawio-studio/references/diagram-patterns.md +60 -0
  96. package/localized/zh-CN/skills/fec-drawio-studio/references/flowchart-quality.md +49 -0
  97. package/localized/zh-CN/skills/fec-drawio-studio/references/layout-and-export.md +72 -0
  98. package/localized/zh-CN/skills/fec-drawio-studio/references/troubleshooting.md +29 -0
  99. package/localized/zh-CN/skills/fec-drawio-studio/references/xml-and-mermaid.md +58 -0
  100. package/localized/zh-CN/skills/fec-drawio-studio/scripts/brand-symbols.mjs +99 -0
  101. package/localized/zh-CN/skills/fec-drawio-studio/scripts/diagram-lint.mjs +205 -0
  102. package/localized/zh-CN/skills/fec-drawio-studio/scripts/diagram-url.mjs +102 -0
  103. package/localized/zh-CN/skills/fec-drawio-studio/scripts/drawio-export.mjs +134 -0
  104. package/localized/zh-CN/skills/fec-drawio-studio/scripts/layout-graph.mjs +107 -0
  105. package/localized/zh-CN/skills/fec-drawio-studio/scripts/png-embed-fix.mjs +26 -0
  106. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-go-packages.mjs +36 -0
  107. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-js-modules.mjs +52 -0
  108. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-python-classes.mjs +30 -0
  109. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-python-modules.mjs +55 -0
  110. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
  111. package/localized/zh-CN/skills/fec-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
  112. package/localized/zh-CN/skills/fec-drawio-studio/scripts/shape-query.mjs +121 -0
  113. package/localized/zh-CN/skills/fec-drawio-studio/scripts/studio-core.mjs +139 -0
  114. package/localized/zh-CN/skills/fec-drawio-studio/styles/built-in/corporate.json +49 -0
  115. package/localized/zh-CN/skills/fec-drawio-studio/styles/built-in/default.json +49 -0
  116. package/localized/zh-CN/skills/fec-drawio-studio/styles/built-in/handdrawn.json +49 -0
  117. package/localized/zh-CN/skills/fec-drawio-studio/styles/schema.json +112 -0
  118. package/localized/zh-CN/skills/fec-e2e-testing/SKILL.md +42 -0
  119. package/localized/zh-CN/skills/fec-e2e-testing/references/e2e-ci-reporting.md +62 -0
  120. package/localized/zh-CN/skills/fec-e2e-testing/references/e2e-special-scenarios.md +52 -0
  121. package/localized/zh-CN/skills/fec-e2e-testing/references/e2e-visual-regression.md +60 -0
  122. package/localized/zh-CN/skills/fec-e2e-testing/references/playwright-patterns.md +95 -0
  123. package/localized/zh-CN/skills/fec-form-handling/SKILL.md +76 -0
  124. package/localized/zh-CN/skills/fec-form-handling/references/advanced-form-patterns.md +101 -0
  125. package/localized/zh-CN/skills/fec-image-generation/SKILL.md +80 -0
  126. package/localized/zh-CN/skills/fec-image-generation/assets/interactive-diagram.html +371 -0
  127. package/localized/zh-CN/skills/fec-image-generation/references/artifact-routing.md +80 -0
  128. package/localized/zh-CN/skills/fec-image-generation/references/diagram-workflows.md +74 -0
  129. package/localized/zh-CN/skills/fec-image-generation/references/html-technical-diagrams.md +236 -0
  130. package/localized/zh-CN/skills/fec-image-generation/references/png-qa-autofix.md +30 -0
  131. package/localized/zh-CN/skills/fec-image-generation/scripts/export-diagram.mjs +364 -0
  132. package/localized/zh-CN/skills/fec-image-generation/scripts/interactive-diagram-server.mjs +654 -0
  133. package/localized/zh-CN/skills/fec-image-generation/scripts/png-qa.mjs +431 -0
  134. package/localized/zh-CN/skills/fec-image-generation/scripts/tech-diagram-render.mjs +1397 -0
  135. package/localized/zh-CN/skills/fec-implement-from-design/SKILL.md +129 -0
  136. package/localized/zh-CN/skills/fec-implement-from-design/references/design-plan-template.md +36 -0
  137. package/localized/zh-CN/skills/fec-legacy-to-modern-migration/SKILL.md +46 -0
  138. package/localized/zh-CN/skills/fec-legacy-to-modern-migration/references/migration-execution-checklist.md +110 -0
  139. package/localized/zh-CN/skills/fec-legacy-to-modern-migration/references/migration-report-template.md +41 -0
  140. package/localized/zh-CN/skills/fec-legacy-to-modern-migration/references/migration-strategy-and-mapping.md +48 -0
  141. package/localized/zh-CN/skills/fec-legacy-web-standard/SKILL.md +35 -0
  142. package/localized/zh-CN/skills/fec-legacy-web-standard/references/legacy-patterns.md +85 -0
  143. package/localized/zh-CN/skills/fec-list-virtualization/SKILL.md +34 -0
  144. package/localized/zh-CN/skills/fec-list-virtualization/references/virtualization-patterns.md +80 -0
  145. package/localized/zh-CN/skills/fec-monorepo-project-standard/SKILL.md +142 -0
  146. package/localized/zh-CN/skills/fec-motion-interaction/SKILL.md +73 -0
  147. package/localized/zh-CN/skills/fec-motion-interaction/references/motion-patterns.md +112 -0
  148. package/localized/zh-CN/skills/fec-nextjs-project-standard/SKILL.md +123 -0
  149. package/localized/zh-CN/skills/fec-nuxt-project-standard/SKILL.md +122 -0
  150. package/localized/zh-CN/skills/fec-performance-optimization/SKILL.md +80 -0
  151. package/localized/zh-CN/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
  152. package/localized/zh-CN/skills/fec-performance-optimization/references/report-template.md +59 -0
  153. package/localized/zh-CN/skills/fec-pwa-implementation/SKILL.md +35 -0
  154. package/localized/zh-CN/skills/fec-pwa-implementation/references/manifest-and-icons.md +53 -0
  155. package/localized/zh-CN/skills/fec-pwa-implementation/references/service-worker-workbox.md +68 -0
  156. package/localized/zh-CN/skills/fec-react-project-standard/SKILL.md +91 -0
  157. package/localized/zh-CN/skills/fec-react-project-standard/references/react-performance-patterns.md +35 -0
  158. package/localized/zh-CN/skills/fec-react-project-standard/references/react-project-structure.md +197 -0
  159. package/localized/zh-CN/skills/fec-react-project-standard/references/react-quality-patterns.md +131 -0
  160. package/localized/zh-CN/skills/fec-react-project-standard/references/react-runtime-patterns.md +293 -0
  161. package/localized/zh-CN/skills/fec-refactor-clean/SKILL.md +51 -0
  162. package/localized/zh-CN/skills/fec-refactor-clean/references/report-template.md +42 -0
  163. package/localized/zh-CN/skills/fec-responsive-layout/SKILL.md +34 -0
  164. package/localized/zh-CN/skills/fec-responsive-layout/references/responsive-layout-patterns.md +70 -0
  165. package/localized/zh-CN/skills/fec-route-protection/SKILL.md +135 -0
  166. package/localized/zh-CN/skills/fec-security-review/SKILL.md +38 -0
  167. package/localized/zh-CN/skills/fec-security-review/references/report-template.md +27 -0
  168. package/localized/zh-CN/skills/fec-security-review/references/security-checklist.md +64 -0
  169. package/localized/zh-CN/skills/fec-source-driven-development/SKILL.md +87 -0
  170. package/localized/zh-CN/skills/fec-state-management/SKILL.md +140 -0
  171. package/localized/zh-CN/skills/fec-state-management/references/state-patterns.md +109 -0
  172. package/localized/zh-CN/skills/fec-storybook-component-doc/SKILL.md +37 -0
  173. package/localized/zh-CN/skills/fec-storybook-component-doc/references/story-patterns.md +118 -0
  174. package/localized/zh-CN/skills/fec-svg-animation/SKILL.md +148 -0
  175. package/localized/zh-CN/skills/fec-tailwind-design-system/SKILL.md +34 -0
  176. package/localized/zh-CN/skills/fec-tailwind-design-system/references/tailwind-system-patterns.md +59 -0
  177. package/localized/zh-CN/skills/fec-tdd-workflow/SKILL.md +52 -0
  178. package/localized/zh-CN/skills/fec-testing-strategy/SKILL.md +45 -0
  179. package/localized/zh-CN/skills/fec-typescript-project-standard/SKILL.md +54 -0
  180. package/{skills/fec-typescript-type-safety → localized/zh-CN/skills/fec-typescript-project-standard}/references/type-safety-patterns.md +1 -1
  181. package/{skills/fec-typescript-type-safety/SKILL.md → localized/zh-CN/skills/fec-typescript-project-standard/references/type-safety.md} +5 -14
  182. package/localized/zh-CN/skills/fec-ui-design/SKILL.md +108 -0
  183. package/localized/zh-CN/skills/fec-ui-design/data/product-rules.json +231 -0
  184. package/localized/zh-CN/skills/fec-ui-design/data/stack-ui-rules.json +146 -0
  185. package/localized/zh-CN/skills/fec-ui-design/data/style-archetypes.json +373 -0
  186. package/localized/zh-CN/skills/fec-ui-design/data/ux-quality-rules.json +203 -0
  187. package/localized/zh-CN/skills/fec-ui-design/references/design-intelligence.md +97 -0
  188. package/localized/zh-CN/skills/fec-ui-design/references/master-page-overrides.md +30 -0
  189. package/localized/zh-CN/skills/fec-ui-design/references/pre-delivery-checklist.md +39 -0
  190. package/localized/zh-CN/skills/fec-ui-design/scripts/design-system.mjs +648 -0
  191. package/localized/zh-CN/skills/fec-validation-fix/SKILL.md +51 -0
  192. package/localized/zh-CN/skills/fec-validation-fix/references/report-template.md +43 -0
  193. package/localized/zh-CN/skills/fec-vite-project-standard/SKILL.md +83 -0
  194. package/localized/zh-CN/skills/fec-vue3-project-standard/SKILL.md +58 -0
  195. package/localized/zh-CN/skills/fec-vue3-project-standard/references/vue3-composables-routing.md +162 -0
  196. package/localized/zh-CN/skills/fec-vue3-project-standard/references/vue3-performance-patterns.md +13 -0
  197. package/localized/zh-CN/skills/fec-vue3-project-standard/references/vue3-project-structure.md +176 -0
  198. package/localized/zh-CN/skills/fec-vue3-project-standard/references/vue3-state-api-quality.md +216 -0
  199. package/localized/zh-CN/skills/fec-web-video-presentation/SKILL.md +61 -0
  200. package/localized/zh-CN/skills/fec-web-video-presentation/data/starter-themes.json +59 -0
  201. package/localized/zh-CN/skills/fec-web-video-presentation/references/chapter-craft.md +37 -0
  202. package/localized/zh-CN/skills/fec-web-video-presentation/references/content-plan.md +38 -0
  203. package/localized/zh-CN/skills/fec-web-video-presentation/references/recording-and-audio.md +33 -0
  204. package/localized/zh-CN/skills/fec-web-video-presentation/references/theme-system.md +36 -0
  205. package/localized/zh-CN/skills/fec-web-video-presentation/scripts/create-video-presentation.mjs +430 -0
  206. package/localized/zh-CN/skills/fec-web-workers/SKILL.md +35 -0
  207. package/localized/zh-CN/skills/fec-web-workers/references/advanced-workers.md +54 -0
  208. package/localized/zh-CN/skills/fec-web-workers/references/basic-worker.md +67 -0
  209. package/localized/zh-CN/skills/metadata.json +1646 -0
  210. package/localized/zh-CN/skills/relations.json +755 -0
  211. package/localized/zh-CN/templates/claude/CLAUDE.md +106 -0
  212. package/localized/zh-CN/templates/claude/settings.json +62 -0
  213. package/localized/zh-CN/templates/codex/AGENTS.md +105 -0
  214. package/localized/zh-CN/templates/codex/config.toml +32 -0
  215. package/localized/zh-CN/templates/openclaw/AGENTS.md +101 -0
  216. package/localized/zh-CN/templates/openclaw/OPENCLAW-CONFIG.md +12 -0
  217. package/localized/zh-CN/templates/shared/rules/fec-agent-workflow.md +54 -0
  218. package/localized/zh-CN/templates/shared/rules/fec-api-layer.md +99 -0
  219. package/localized/zh-CN/templates/shared/rules/fec-ci-cd.md +40 -0
  220. package/localized/zh-CN/templates/shared/rules/fec-code-comments.md +33 -0
  221. package/localized/zh-CN/templates/shared/rules/fec-design-system.md +72 -0
  222. package/localized/zh-CN/templates/shared/rules/fec-error-handling.md +56 -0
  223. package/localized/zh-CN/templates/shared/rules/fec-git-conventions.md +73 -0
  224. package/localized/zh-CN/templates/shared/rules/fec-i18n.md +64 -0
  225. package/localized/zh-CN/templates/shared/rules/fec-naming-conventions.md +120 -0
  226. package/localized/zh-CN/templates/shared/rules/fec-performance.md +101 -0
  227. package/localized/zh-CN/templates/shared/rules/fec-react.md +82 -0
  228. package/localized/zh-CN/templates/shared/rules/fec-refactoring.md +47 -0
  229. package/localized/zh-CN/templates/shared/rules/fec-rendering-patterns.md +40 -0
  230. package/localized/zh-CN/templates/shared/rules/fec-responsive-design.md +50 -0
  231. package/localized/zh-CN/templates/shared/rules/fec-source-driven-development.md +31 -0
  232. package/localized/zh-CN/templates/shared/rules/fec-state-management.md +60 -0
  233. package/localized/zh-CN/templates/shared/rules/fec-testing.md +98 -0
  234. package/localized/zh-CN/templates/shared/rules/fec-typescript.md +112 -0
  235. package/localized/zh-CN/templates/shared/rules/fec-vue.md +64 -0
  236. package/localized/zh-CN/templates/shared/rules/fec-working-modes.md +50 -0
  237. package/openclaw.plugin.json +1 -1
  238. package/package.json +4 -3
  239. package/skills/TEMPLATE.md +74 -74
  240. package/skills/eval_queries.json +717 -619
  241. package/skills/fec-accessibility-check/SKILL.md +21 -21
  242. package/skills/fec-accessibility-check/references/report-template.md +12 -12
  243. package/skills/fec-accessibility-check/references/screen-reader-testing.md +24 -24
  244. package/skills/fec-alchemy/SKILL.md +50 -50
  245. package/skills/fec-alchemy/assets/absorption-plan-template.md +32 -32
  246. package/skills/fec-alchemy/assets/intake-template.md +55 -55
  247. package/skills/fec-alchemy/assets/review-checklist.md +23 -23
  248. package/skills/fec-alchemy/references/methodology.md +66 -66
  249. package/skills/fec-alchemy/references/originality-and-licensing.md +42 -42
  250. package/skills/fec-api-integration/SKILL.md +61 -61
  251. package/skills/fec-api-integration/references/integration-patterns.md +30 -30
  252. package/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
  253. package/skills/fec-browser-storage/SKILL.md +16 -16
  254. package/skills/fec-browser-storage/references/storage-patterns.md +16 -16
  255. package/skills/fec-canvas-threejs/SKILL.md +21 -21
  256. package/skills/fec-canvas-threejs/references/rendering-patterns.md +10 -10
  257. package/skills/fec-canvas-threejs/references/shader-webgl-patterns.md +37 -37
  258. package/skills/fec-code-review/SKILL.md +94 -94
  259. package/skills/fec-code-review/references/report-template.md +13 -13
  260. package/skills/fec-component-testing/SKILL.md +39 -39
  261. package/skills/fec-data-fetching/SKILL.md +16 -16
  262. package/skills/fec-data-fetching/references/query-patterns.md +27 -27
  263. package/skills/fec-debug-framework/SKILL.md +95 -95
  264. package/skills/fec-debug-framework/references/report-template.md +34 -34
  265. package/skills/fec-dependency-upgrade/SKILL.md +17 -17
  266. package/skills/fec-dependency-upgrade/references/dependency-upgrade-workflow.md +31 -31
  267. package/skills/fec-doc-sync/SKILL.md +23 -23
  268. package/skills/fec-drawio-studio/SKILL.md +73 -0
  269. package/skills/fec-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
  270. package/skills/fec-drawio-studio/data/brand-icons.json +878 -0
  271. package/skills/fec-drawio-studio/data/shape-index.json +83570 -0
  272. package/skills/fec-drawio-studio/references/data-residency.md +27 -0
  273. package/skills/fec-drawio-studio/references/diagram-patterns.md +60 -0
  274. package/skills/fec-drawio-studio/references/flowchart-quality.md +49 -0
  275. package/skills/fec-drawio-studio/references/layout-and-export.md +72 -0
  276. package/skills/fec-drawio-studio/references/troubleshooting.md +29 -0
  277. package/skills/fec-drawio-studio/references/xml-and-mermaid.md +58 -0
  278. package/skills/fec-drawio-studio/scripts/brand-symbols.mjs +99 -0
  279. package/skills/fec-drawio-studio/scripts/diagram-lint.mjs +205 -0
  280. package/skills/fec-drawio-studio/scripts/diagram-url.mjs +102 -0
  281. package/skills/fec-drawio-studio/scripts/drawio-export.mjs +134 -0
  282. package/skills/fec-drawio-studio/scripts/layout-graph.mjs +107 -0
  283. package/skills/fec-drawio-studio/scripts/png-embed-fix.mjs +26 -0
  284. package/skills/fec-drawio-studio/scripts/scan-go-packages.mjs +36 -0
  285. package/skills/fec-drawio-studio/scripts/scan-js-modules.mjs +52 -0
  286. package/skills/fec-drawio-studio/scripts/scan-python-classes.mjs +30 -0
  287. package/skills/fec-drawio-studio/scripts/scan-python-modules.mjs +55 -0
  288. package/skills/fec-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
  289. package/skills/fec-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
  290. package/skills/fec-drawio-studio/scripts/shape-query.mjs +121 -0
  291. package/skills/fec-drawio-studio/scripts/studio-core.mjs +139 -0
  292. package/skills/fec-drawio-studio/styles/built-in/corporate.json +49 -0
  293. package/skills/fec-drawio-studio/styles/built-in/default.json +49 -0
  294. package/skills/fec-drawio-studio/styles/built-in/handdrawn.json +49 -0
  295. package/skills/fec-drawio-studio/styles/schema.json +112 -0
  296. package/skills/fec-e2e-testing/SKILL.md +24 -22
  297. package/skills/fec-e2e-testing/references/e2e-ci-reporting.md +62 -0
  298. package/skills/fec-e2e-testing/references/e2e-special-scenarios.md +52 -0
  299. package/skills/fec-e2e-testing/references/e2e-visual-regression.md +60 -0
  300. package/skills/fec-e2e-testing/references/playwright-patterns.md +6 -6
  301. package/skills/fec-form-handling/SKILL.md +21 -21
  302. package/skills/fec-form-handling/references/advanced-form-patterns.md +41 -41
  303. package/skills/fec-image-generation/SKILL.md +81 -0
  304. package/skills/fec-image-generation/assets/interactive-diagram.html +371 -0
  305. package/skills/fec-image-generation/references/artifact-routing.md +80 -0
  306. package/skills/fec-image-generation/references/diagram-workflows.md +74 -0
  307. package/skills/fec-image-generation/references/html-technical-diagrams.md +236 -0
  308. package/skills/fec-image-generation/references/png-qa-autofix.md +30 -0
  309. package/skills/fec-image-generation/scripts/export-diagram.mjs +364 -0
  310. package/skills/fec-image-generation/scripts/interactive-diagram-server.mjs +654 -0
  311. package/skills/fec-image-generation/scripts/png-qa.mjs +431 -0
  312. package/skills/fec-image-generation/scripts/tech-diagram-render.mjs +1397 -0
  313. package/skills/fec-implement-from-design/SKILL.md +81 -74
  314. package/skills/fec-implement-from-design/references/design-plan-template.md +16 -16
  315. package/skills/fec-legacy-to-modern-migration/SKILL.md +29 -173
  316. package/skills/fec-legacy-to-modern-migration/references/migration-execution-checklist.md +110 -0
  317. package/skills/fec-legacy-to-modern-migration/references/migration-report-template.md +37 -37
  318. package/skills/fec-legacy-to-modern-migration/references/migration-strategy-and-mapping.md +48 -0
  319. package/skills/fec-legacy-web-standard/SKILL.md +17 -17
  320. package/skills/fec-legacy-web-standard/references/legacy-patterns.md +16 -16
  321. package/skills/fec-list-virtualization/SKILL.md +16 -16
  322. package/skills/fec-list-virtualization/references/virtualization-patterns.md +31 -31
  323. package/skills/fec-monorepo-project-standard/SKILL.md +52 -52
  324. package/skills/fec-motion-interaction/SKILL.md +51 -44
  325. package/skills/fec-motion-interaction/references/motion-patterns.md +11 -11
  326. package/skills/fec-nextjs-project-standard/SKILL.md +64 -58
  327. package/skills/fec-nuxt-project-standard/SKILL.md +57 -57
  328. package/skills/fec-performance-optimization/SKILL.md +54 -50
  329. package/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
  330. package/skills/fec-performance-optimization/references/report-template.md +34 -28
  331. package/skills/fec-pwa-implementation/SKILL.md +17 -17
  332. package/skills/fec-pwa-implementation/references/manifest-and-icons.md +12 -12
  333. package/skills/fec-pwa-implementation/references/service-worker-workbox.md +13 -13
  334. package/skills/fec-react-project-standard/SKILL.md +72 -64
  335. package/skills/fec-react-project-standard/references/react-performance-patterns.md +35 -0
  336. package/skills/fec-react-project-standard/references/react-project-structure.md +197 -0
  337. package/skills/fec-react-project-standard/references/react-quality-patterns.md +131 -0
  338. package/skills/fec-react-project-standard/references/react-runtime-patterns.md +293 -0
  339. package/skills/fec-refactor-clean/SKILL.md +30 -30
  340. package/skills/fec-refactor-clean/references/report-template.md +23 -23
  341. package/skills/fec-responsive-layout/SKILL.md +17 -17
  342. package/skills/fec-responsive-layout/references/responsive-layout-patterns.md +39 -28
  343. package/skills/fec-route-protection/SKILL.md +26 -26
  344. package/skills/fec-security-review/SKILL.md +20 -20
  345. package/skills/fec-security-review/references/report-template.md +12 -12
  346. package/skills/fec-security-review/references/security-checklist.md +27 -27
  347. package/skills/fec-source-driven-development/SKILL.md +66 -40
  348. package/skills/fec-state-management/SKILL.md +34 -34
  349. package/skills/fec-state-management/references/state-patterns.md +19 -19
  350. package/skills/fec-storybook-component-doc/SKILL.md +19 -19
  351. package/skills/fec-storybook-component-doc/references/story-patterns.md +12 -12
  352. package/skills/fec-svg-animation/SKILL.md +32 -32
  353. package/skills/fec-tailwind-design-system/SKILL.md +17 -17
  354. package/skills/fec-tailwind-design-system/references/tailwind-system-patterns.md +36 -32
  355. package/skills/fec-tdd-workflow/SKILL.md +28 -28
  356. package/skills/fec-testing-strategy/SKILL.md +29 -29
  357. package/skills/fec-typescript-project-standard/SKILL.md +54 -0
  358. package/skills/fec-typescript-project-standard/references/type-safety-patterns.md +102 -0
  359. package/skills/fec-typescript-project-standard/references/type-safety.md +148 -0
  360. package/skills/fec-ui-design/SKILL.md +90 -72
  361. package/skills/fec-ui-design/data/style-archetypes.json +40 -0
  362. package/skills/fec-ui-design/data/ux-quality-rules.json +35 -0
  363. package/skills/fec-ui-design/references/design-intelligence.md +81 -21
  364. package/skills/fec-ui-design/references/master-page-overrides.md +15 -15
  365. package/skills/fec-ui-design/references/pre-delivery-checklist.md +38 -32
  366. package/skills/fec-ui-design/scripts/design-system.mjs +119 -1
  367. package/skills/fec-validation-fix/SKILL.md +26 -26
  368. package/skills/fec-validation-fix/references/report-template.md +25 -25
  369. package/skills/fec-vite-project-standard/SKILL.md +39 -39
  370. package/skills/fec-vue3-project-standard/SKILL.md +39 -30
  371. package/skills/fec-vue3-project-standard/references/vue3-composables-routing.md +163 -0
  372. package/skills/fec-vue3-project-standard/references/vue3-performance-patterns.md +13 -0
  373. package/skills/fec-vue3-project-standard/references/vue3-project-structure.md +177 -0
  374. package/skills/fec-vue3-project-standard/references/vue3-state-api-quality.md +216 -0
  375. package/skills/fec-web-video-presentation/SKILL.md +61 -0
  376. package/skills/fec-web-video-presentation/data/starter-themes.json +59 -0
  377. package/skills/fec-web-video-presentation/references/chapter-craft.md +37 -0
  378. package/skills/fec-web-video-presentation/references/content-plan.md +38 -0
  379. package/skills/fec-web-video-presentation/references/recording-and-audio.md +33 -0
  380. package/skills/fec-web-video-presentation/references/theme-system.md +36 -0
  381. package/skills/fec-web-video-presentation/scripts/create-video-presentation.mjs +430 -0
  382. package/skills/fec-web-workers/SKILL.md +16 -16
  383. package/skills/fec-web-workers/references/advanced-workers.md +13 -13
  384. package/skills/fec-web-workers/references/basic-worker.md +8 -8
  385. package/skills/metadata.json +402 -220
  386. package/skills/relations.json +120 -25
  387. package/templates/claude/CLAUDE.md +60 -60
  388. package/templates/codex/AGENTS.md +76 -76
  389. package/templates/codex/config.toml +4 -4
  390. package/templates/openclaw/AGENTS.md +68 -68
  391. package/templates/openclaw/OPENCLAW-CONFIG.md +8 -8
  392. package/templates/shared/rules/fec-agent-workflow.md +40 -40
  393. package/templates/shared/rules/fec-api-layer.md +52 -52
  394. package/templates/shared/rules/fec-ci-cd.md +29 -117
  395. package/templates/shared/rules/fec-code-comments.md +22 -22
  396. package/templates/shared/rules/fec-design-system.md +65 -241
  397. package/templates/shared/rules/fec-error-handling.md +41 -185
  398. package/templates/shared/rules/fec-git-conventions.md +42 -42
  399. package/templates/shared/rules/fec-i18n.md +48 -96
  400. package/templates/shared/rules/fec-naming-conventions.md +91 -91
  401. package/templates/shared/rules/fec-performance.md +78 -78
  402. package/templates/shared/rules/fec-react.md +58 -58
  403. package/templates/shared/rules/fec-refactoring.md +34 -30
  404. package/templates/shared/rules/fec-rendering-patterns.md +40 -183
  405. package/templates/shared/rules/fec-responsive-design.md +37 -214
  406. package/templates/shared/rules/fec-source-driven-development.md +22 -22
  407. package/templates/shared/rules/fec-state-management.md +45 -148
  408. package/templates/shared/rules/fec-testing.md +64 -64
  409. package/templates/shared/rules/fec-typescript.md +98 -341
  410. package/templates/shared/rules/fec-vue.md +42 -42
  411. package/templates/shared/rules/fec-working-modes.md +34 -34
  412. package/skills/fec-e2e-testing/references/e2e-advanced.md +0 -176
  413. package/skills/fec-react-project-standard/references/react-project-details.md +0 -642
  414. package/skills/fec-vue3-project-standard/references/vue3-project-details.md +0 -547
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import zlib from "node:zlib";
3
+ import { parseArgs, readText } from "./studio-core.mjs";
4
+
5
+ const args = parseArgs(process.argv.slice(2));
6
+ const input = args._[0];
7
+ if (!input) {
8
+ console.error(
9
+ "usage: node diagram-url.mjs <diagram-file> [--edit|--create] [--type xml|mermaid|csv] [--lightbox] [--dark true|false|auto] [--base-url URL] [--json|--shortcut]",
10
+ );
11
+ process.exit(2);
12
+ }
13
+
14
+ export function encodeDiagramXml(xml) {
15
+ const encoded = encodeURIComponent(xml);
16
+ return zlib.deflateRawSync(Buffer.from(encoded, "utf8")).toString("base64");
17
+ }
18
+
19
+ export function viewerUrl(xml, options = {}) {
20
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://viewer.diagrams.net/");
21
+ return `${baseUrl}?highlight=0000ff&edit=_blank#R${encodeDiagramXml(xml)}`;
22
+ }
23
+
24
+ export function editorUrl(xml, options = {}) {
25
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://app.diagrams.net/");
26
+ return `${baseUrl}?offline=1#R${encodeDiagramXml(xml)}`;
27
+ }
28
+
29
+ export function createUrl(content, options = {}) {
30
+ const type = normalizeType(options.type);
31
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? "https://app.diagrams.net/");
32
+ const params = new URLSearchParams();
33
+ if (options.lightbox) {
34
+ params.set("lightbox", "1");
35
+ params.set("edit", "_blank");
36
+ } else {
37
+ params.set("grid", "0");
38
+ params.set("pv", "0");
39
+ params.set("edit", "_blank");
40
+ }
41
+ params.set("border", String(options.border ?? 10));
42
+ const dark = normalizeDark(options.dark);
43
+ if (dark === true) params.set("dark", "1");
44
+
45
+ const payload = encodeURIComponent(
46
+ JSON.stringify({
47
+ type,
48
+ compressed: true,
49
+ data: encodeDiagramXml(content),
50
+ }),
51
+ );
52
+ const query = params.toString();
53
+ return `${baseUrl}${query ? `?${query}` : ""}#create=${payload}`;
54
+ }
55
+
56
+ export function internetShortcut(url) {
57
+ return `[InternetShortcut]\r\nURL=${url}\r\n`;
58
+ }
59
+
60
+ function normalizeType(value = "xml") {
61
+ if (["xml", "mermaid", "csv"].includes(value)) return value;
62
+ throw new Error(`Unsupported diagram type "${value}". Expected xml, mermaid, or csv.`);
63
+ }
64
+
65
+ function normalizeDark(value = "auto") {
66
+ if (value === true || value === "true") return true;
67
+ if (value === false || value === "false") return false;
68
+ if (value === "auto" || value === undefined) return "auto";
69
+ throw new Error(`Unsupported dark mode "${value}". Expected true, false, or auto.`);
70
+ }
71
+
72
+ function normalizeBaseUrl(value) {
73
+ return String(value).replace(/[?#].*$/, "").replace(/\/?$/, "/");
74
+ }
75
+
76
+ try {
77
+ const content = readText(input);
78
+ const type = normalizeType(args.type ?? "xml");
79
+ if (type !== "xml" && !args.create) {
80
+ throw new Error("Mermaid and CSV inputs require --create because viewer/editor #R URLs only load XML.");
81
+ }
82
+ const options = {
83
+ baseUrl: args.baseUrl,
84
+ border: args.border,
85
+ dark: args.dark,
86
+ lightbox: Boolean(args.lightbox),
87
+ type,
88
+ };
89
+ const mode = args.create ? "create" : args.edit ? "edit" : "view";
90
+ const url = args.create ? createUrl(content, options) : args.edit ? editorUrl(content, options) : viewerUrl(content, options);
91
+ const shortcut = internetShortcut(url);
92
+ if (args.shortcut) {
93
+ process.stdout.write(shortcut);
94
+ } else if (args.json) {
95
+ process.stdout.write(`${JSON.stringify({ url, mode, type, windowsShortcut: shortcut }, null, 2)}\n`);
96
+ } else {
97
+ process.stdout.write(`${url}\n`);
98
+ }
99
+ } catch (error) {
100
+ console.error(error instanceof Error ? error.message : String(error));
101
+ process.exit(1);
102
+ }
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ import { formatResult, parseArgs } from "./studio-core.mjs";
7
+
8
+ const INSTALL_HINTS = [
9
+ "draw.io desktop CLI was not found.",
10
+ "Install draw.io desktop, then rerun the export.",
11
+ "Windows: winget install JGraph.Draw",
12
+ "macOS: brew install --cask drawio",
13
+ "Linux: install drawio from your package manager or snap install drawio",
14
+ "Manual download: https://github.com/jgraph/drawio-desktop/releases",
15
+ ];
16
+
17
+ export function buildExportPlan(input, args = {}, env = process.env, platform = process.platform) {
18
+ const drawio = findDrawio(args.drawio, env, platform);
19
+ if (!drawio) {
20
+ return {
21
+ ok: false,
22
+ title: "Draw.io Export",
23
+ errors: [INSTALL_HINTS.join("\n")],
24
+ command: null,
25
+ };
26
+ }
27
+
28
+ const format = String(args.format ?? "png");
29
+ const output = String(args.output ?? defaultOutput(input, format));
30
+ const commandArgs = ["-x", "-f", format];
31
+ if (args.embed) commandArgs.push("-e");
32
+ if (args.scale) commandArgs.push("-s", String(args.scale));
33
+ if (args.width) commandArgs.push("--width", String(args.width));
34
+ if (args.border) commandArgs.push("--border", String(args.border));
35
+ if (args.crop) commandArgs.push("--crop");
36
+ if (args.page !== undefined) commandArgs.push("-p", String(args.page));
37
+ commandArgs.push("-o", output, input);
38
+
39
+ return {
40
+ ok: true,
41
+ title: "Draw.io Export",
42
+ drawio,
43
+ command: [drawio, ...commandArgs],
44
+ output,
45
+ format,
46
+ dryRun: Boolean(args.dryRun),
47
+ errors: [],
48
+ };
49
+ }
50
+
51
+ export function findDrawio(explicitPath, env = process.env, platform = process.platform) {
52
+ if (explicitPath) return existingFile(explicitPath);
53
+
54
+ for (const command of ["drawio", "draw.io"]) {
55
+ const found = findOnPath(command, env, platform);
56
+ if (found) return found;
57
+ }
58
+
59
+ for (const candidate of defaultCandidates(env, platform)) {
60
+ const found = existingFile(candidate);
61
+ if (found) return found;
62
+ }
63
+
64
+ return null;
65
+ }
66
+
67
+ function findOnPath(command, env, platform) {
68
+ const pathValue = env.PATH ?? env.Path ?? "";
69
+ const dirs = pathValue.split(path.delimiter).filter(Boolean);
70
+ const extensions = platform === "win32" ? pathExtensions(env) : [""];
71
+ for (const dir of dirs) {
72
+ for (const ext of extensions) {
73
+ const candidate = path.join(dir, command.endsWith(ext) ? command : `${command}${ext}`);
74
+ const found = existingFile(candidate);
75
+ if (found) return found;
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+
81
+ function pathExtensions(env) {
82
+ const configured = env.PATHEXT ? env.PATHEXT.split(";").filter(Boolean) : [".EXE", ".CMD", ".BAT", ""];
83
+ return [...new Set(["", ...configured, ...configured.map((item) => item.toLowerCase())])];
84
+ }
85
+
86
+ function defaultCandidates(env, platform) {
87
+ if (platform === "win32") {
88
+ return [
89
+ path.join(env.ProgramFiles ?? "C:\\Program Files", "draw.io", "draw.io.exe"),
90
+ path.join(env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "draw.io", "draw.io.exe"),
91
+ path.join(env.LOCALAPPDATA ?? path.join(os.homedir(), "AppData", "Local"), "Programs", "draw.io", "draw.io.exe"),
92
+ ];
93
+ }
94
+ if (platform === "darwin") {
95
+ return ["/Applications/draw.io.app/Contents/MacOS/draw.io"];
96
+ }
97
+ return ["/usr/bin/drawio", "/usr/local/bin/drawio", "/snap/bin/drawio"];
98
+ }
99
+
100
+ function existingFile(candidate) {
101
+ if (!candidate) return null;
102
+ const resolved = path.resolve(candidate);
103
+ return fs.existsSync(resolved) && fs.statSync(resolved).isFile() ? resolved : null;
104
+ }
105
+
106
+ function defaultOutput(input, format) {
107
+ return `${input.replace(/\.(drawio|xml)$/i, "")}.${format}`;
108
+ }
109
+
110
+ function printFailure(plan, args) {
111
+ const output = formatResult(plan, args.formatOutput ?? (args.json ? "json" : "markdown"));
112
+ process.stderr.write(output);
113
+ }
114
+
115
+ const args = parseArgs(process.argv.slice(2));
116
+ const input = args._[0];
117
+ if (!input) {
118
+ console.error("usage: node drawio-export.mjs <file.drawio> [--format png|svg|pdf] [--output file] [--scale 2] [--width 2000] [--border 20] [--dry-run] [--json]");
119
+ process.exit(2);
120
+ }
121
+
122
+ const plan = buildExportPlan(input, args);
123
+ if (!plan.ok) {
124
+ printFailure(plan, args);
125
+ process.exit(1);
126
+ }
127
+
128
+ if (args.dryRun) {
129
+ process.stdout.write(formatResult(plan, args.formatOutput ?? (args.json ? "json" : "markdown")));
130
+ process.exit(0);
131
+ }
132
+
133
+ const result = spawnSync(plan.command[0], plan.command.slice(1), { stdio: "inherit" });
134
+ process.exit(result.status ?? 1);
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { parseArgs, printOrWrite, readText, snap, writeText, xmlEscape } from "./studio-core.mjs";
4
+
5
+ const DEFAULT_W = 140;
6
+ const DEFAULT_H = 64;
7
+ const NODE_STYLE = "rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;";
8
+ const EDGE_STYLE = "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;";
9
+ const PALETTE = [
10
+ ["#dae8fc", "#6c8ebf"], ["#d5e8d4", "#82b366"], ["#ffe6cc", "#d79b00"],
11
+ ["#e1d5e7", "#9673a6"], ["#fff2cc", "#d6b656"], ["#f8cecc", "#b85450"],
12
+ ];
13
+
14
+ export function buildDot(graph) {
15
+ const direction = String(graph.direction ?? "TB").toUpperCase() === "LR" ? "LR" : "TB";
16
+ const lines = [`digraph G { rankdir=${direction}; splines=ortho; node [shape=box fixedsize=true];`];
17
+ for (const node of graph.nodes) {
18
+ lines.push(`"${escapeDot(node.id)}" [width=${Number(node.width ?? DEFAULT_W) / 72} height=${Number(node.height ?? DEFAULT_H) / 72}];`);
19
+ }
20
+ for (const edge of graph.edges ?? []) lines.push(`"${escapeDot(edge.source)}" -> "${escapeDot(edge.target)}";`);
21
+ lines.push("}");
22
+ return lines.join("\n");
23
+ }
24
+
25
+ export function runDot(dot) {
26
+ const proc = spawnSync("dot", ["-Tplain"], { input: dot, encoding: "utf8" });
27
+ if (proc.error?.code === "ENOENT") throw new Error("Graphviz `dot` not found on PATH");
28
+ if (proc.status !== 0) throw new Error(`Graphviz failed: ${proc.stderr.trim()}`);
29
+ const pos = new Map();
30
+ let height = 0;
31
+ for (const line of proc.stdout.split(/\r?\n/)) {
32
+ const parts = splitPlain(line);
33
+ if (parts[0] === "graph") height = Number(parts[3]);
34
+ if (parts[0] === "node") pos.set(parts[1], { x: Number(parts[2]), y: Number(parts[3]) });
35
+ }
36
+ return { height, pos };
37
+ }
38
+
39
+ export function graphToDrawio(graph, layout) {
40
+ const groups = [...new Set((graph.nodes ?? []).map((node) => node.group).filter(Boolean))];
41
+ const groupColor = (group) => PALETTE[Math.max(0, groups.indexOf(group)) % PALETTE.length];
42
+ const cells = [];
43
+ const manifest = { nodes: {}, edges: graph.edges ?? [] };
44
+ for (const node of graph.nodes ?? []) {
45
+ const p = layout.pos.get(node.id);
46
+ if (!p) continue;
47
+ const w = Number(node.width ?? DEFAULT_W);
48
+ const h = Number(node.height ?? DEFAULT_H);
49
+ const x = snap(p.x * 72 - w / 2 + 40);
50
+ const y = snap((layout.height - p.y) * 72 - h / 2 + 40);
51
+ const style = node.style ?? (node.group ? tintStyle(groupColor(node.group)) : NODE_STYLE);
52
+ manifest.nodes[node.id] = { x, y, width: w, height: h, group: node.group ?? null };
53
+ cells.push(` <mxCell id="${xmlEscape(node.id)}" value="${xmlEscape(node.label ?? node.id)}" style="${xmlEscape(style)}" vertex="1" parent="1">
54
+ <mxGeometry x="${x}" y="${y}" width="${w}" height="${h}" as="geometry"/>
55
+ </mxCell>`);
56
+ }
57
+ let edgeIndex = 0;
58
+ for (const edge of graph.edges ?? []) {
59
+ cells.push(` <mxCell id="edge_${edgeIndex++}" value="${xmlEscape(edge.label ?? "")}" style="${EDGE_STYLE}" edge="1" parent="1" source="${xmlEscape(edge.source)}" target="${xmlEscape(edge.target)}">
60
+ <mxGeometry relative="1" as="geometry"/>
61
+ </mxCell>`);
62
+ }
63
+ return {
64
+ manifest,
65
+ xml: `<mxfile host="drawio">
66
+ <diagram name="Page-1">
67
+ <mxGraphModel grid="1" gridSize="10" page="1" pageWidth="1100" pageHeight="850">
68
+ <root>
69
+ <mxCell id="0"/>
70
+ <mxCell id="1" parent="0"/>
71
+ ${cells.join("\n")}
72
+ </root>
73
+ </mxGraphModel>
74
+ </diagram>
75
+ </mxfile>
76
+ `,
77
+ };
78
+ }
79
+
80
+ function tintStyle([fill, stroke]) {
81
+ return `rounded=1;whiteSpace=wrap;html=1;fillColor=${fill};strokeColor=${stroke};`;
82
+ }
83
+
84
+ function escapeDot(value) {
85
+ return String(value).replaceAll("\\", "\\\\").replaceAll('"', '\\"');
86
+ }
87
+
88
+ function splitPlain(line) {
89
+ return line.match(/"[^"]*"|\S+/g)?.map((part) => part.replace(/^"|"$/g, "")) ?? [];
90
+ }
91
+
92
+ const args = parseArgs(process.argv.slice(2));
93
+ const input = args._[0];
94
+ if (!input) {
95
+ console.error("usage: node layout-graph.mjs graph.json --output diagram.drawio [--manifest layout.json]");
96
+ process.exit(2);
97
+ }
98
+ try {
99
+ const graph = JSON.parse(readText(input));
100
+ const rendered = graphToDrawio(graph, runDot(buildDot(graph)));
101
+ printOrWrite(rendered.xml, args.output);
102
+ if (args.manifest) writeText(args.manifest, `${JSON.stringify(rendered.manifest, null, 2)}\n`);
103
+ if (!args.output) process.stderr.write(`rendered ${graph.nodes.length} nodes\n`);
104
+ } catch (error) {
105
+ console.error(`error: ${error.message}`);
106
+ process.exit(1);
107
+ }
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import { parseArgs } from "./studio-core.mjs";
4
+
5
+ const IEND = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]);
6
+ const IEND_TAIL = IEND.subarray(4);
7
+
8
+ export function repairPngBuffer(buffer) {
9
+ if (buffer.subarray(-12).equals(IEND)) return { buffer, changed: false, reason: "already-valid" };
10
+ if (buffer.subarray(-4).equals(IEND.subarray(0, 4))) {
11
+ return { buffer: Buffer.concat([buffer, IEND_TAIL]), changed: true, reason: "appended-iend-tail" };
12
+ }
13
+ return { buffer, changed: false, reason: "not-truncated-iend" };
14
+ }
15
+
16
+ const args = parseArgs(process.argv.slice(2));
17
+ const input = args._[0];
18
+ if (!input) {
19
+ console.error("usage: node png-embed-fix.mjs <file.png> [--json]");
20
+ process.exit(2);
21
+ }
22
+
23
+ const repaired = repairPngBuffer(fs.readFileSync(input));
24
+ if (repaired.changed) fs.writeFileSync(input, repaired.buffer);
25
+ const result = { file: input, changed: repaired.changed, reason: repaired.reason };
26
+ process.stdout.write(args.json ? `${JSON.stringify(result, null, 2)}\n` : `${input}: ${repaired.reason}\n`);
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parseArgs, printOrWrite, reduceTransitive, toPosix, walkFiles } from "./studio-core.mjs";
5
+
6
+ export function scanGoPackages(root) {
7
+ const absRoot = path.resolve(root);
8
+ const mod = fs.existsSync(path.join(absRoot, "go.mod")) ? fs.readFileSync(path.join(absRoot, "go.mod"), "utf8").match(/^module\s+(.+)$/m)?.[1] : "";
9
+ const files = walkFiles(absRoot, (file) => file.endsWith(".go") && !file.endsWith("_test.go"));
10
+ const packageDirs = [...new Set(files.map((file) => path.dirname(file)))].sort();
11
+ const dirToId = new Map(packageDirs.map((dir) => [dir, mod ? `${mod}/${toPosix(path.relative(absRoot, dir))}`.replace(/\/$/, "") : toPosix(path.relative(absRoot, dir) || ".")]));
12
+ const nodes = [...dirToId.entries()].map(([dir, id]) => ({ id, label: path.basename(dir), group: toPosix(path.dirname(path.relative(absRoot, dir))).replace(".", "") || undefined }));
13
+ const ids = new Set(nodes.map((node) => node.id));
14
+ const edges = [];
15
+ for (const file of files) {
16
+ const source = dirToId.get(path.dirname(file));
17
+ const text = fs.readFileSync(file, "utf8");
18
+ for (const spec of extractGoImports(text)) if (ids.has(spec)) edges.push({ source, target: spec });
19
+ }
20
+ return { direction: "LR", nodes, edges: reduceTransitive(nodes, edges) };
21
+ }
22
+
23
+ function extractGoImports(text) {
24
+ const out = [];
25
+ for (const match of text.matchAll(/import\s+(?:[._A-Za-z]\w*\s+)?(?:"([^"]+)"|\(([\s\S]*?)\))/g)) {
26
+ if (match[1]) out.push(match[1]);
27
+ if (match[2]) for (const line of match[2].split(/\r?\n/)) {
28
+ const item = line.match(/"([^"]+)"/)?.[1];
29
+ if (item) out.push(item);
30
+ }
31
+ }
32
+ return out;
33
+ }
34
+
35
+ const args = parseArgs(process.argv.slice(2));
36
+ printOrWrite(`${JSON.stringify(scanGoPackages(args._[0] ?? "."), null, 2)}\n`, args.output);
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { parseArgs, printOrWrite, reduceTransitive, toPosix, walkFiles } from "./studio-core.mjs";
6
+
7
+ const JS_EXTS = [".js", ".jsx", ".mjs", ".cjs"];
8
+ const IMPORT_RE = /\bimport\s+(?:[^'"]+?\s+from\s+)?['"]([^'"]+)['"]|\bexport\s+[^'"]*?\s+from\s+['"]([^'"]+)['"]|\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)|\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
9
+
10
+ export function scanJavaScriptModules(root, extensions = JS_EXTS) {
11
+ return scanModules(root, extensions);
12
+ }
13
+
14
+ export function scanModules(root, extensions) {
15
+ const absRoot = path.resolve(root);
16
+ const files = walkFiles(absRoot, (file) => extensions.includes(path.extname(file)));
17
+ const byBase = new Map();
18
+ const nodes = files.map((file) => {
19
+ const id = toPosix(path.relative(absRoot, file)).replace(/\.[^.]+$/, "");
20
+ byBase.set(path.resolve(file), id);
21
+ return { id, label: id.split("/").pop(), group: id.includes("/") ? id.split("/").slice(0, -1).join("/") : undefined };
22
+ });
23
+ const edges = [];
24
+ for (const file of files) {
25
+ const source = byBase.get(path.resolve(file));
26
+ const text = fs.readFileSync(file, "utf8");
27
+ for (const match of text.matchAll(IMPORT_RE)) {
28
+ const spec = match[1] ?? match[2] ?? match[3] ?? match[4];
29
+ if (!spec?.startsWith(".")) continue;
30
+ const target = resolveRelative(file, spec, extensions, byBase);
31
+ if (target) edges.push({ source, target });
32
+ }
33
+ }
34
+ return { direction: "LR", nodes, edges: reduceTransitive(nodes, edges) };
35
+ }
36
+
37
+ function resolveRelative(fromFile, spec, extensions, byBase) {
38
+ const base = path.resolve(path.dirname(fromFile), spec);
39
+ const candidates = [base, ...extensions.map((ext) => base + ext), ...extensions.map((ext) => path.join(base, `index${ext}`))];
40
+ for (const candidate of candidates) {
41
+ const id = byBase.get(path.resolve(candidate));
42
+ if (id) return id;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
48
+ const args = parseArgs(process.argv.slice(2));
49
+ const root = args._[0] ?? ".";
50
+ const graph = scanJavaScriptModules(root);
51
+ printOrWrite(`${JSON.stringify(graph, null, 2)}\n`, args.output);
52
+ }
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parseArgs, printOrWrite, reduceTransitive, toPosix, walkFiles } from "./studio-core.mjs";
5
+
6
+ export function scanPythonClasses(root) {
7
+ const absRoot = path.resolve(root);
8
+ const files = walkFiles(absRoot, (file) => file.endsWith(".py"));
9
+ const classes = [];
10
+ for (const file of files) {
11
+ const moduleId = toPosix(path.relative(absRoot, file)).replace(/\/__init__\.py$/, "").replace(/\.py$/, "").replaceAll("/", ".");
12
+ const text = fs.readFileSync(file, "utf8");
13
+ for (const match of text.matchAll(/^\s*class\s+([A-Za-z_]\w*)\s*(?:\(([^)]*)\))?:/gm)) {
14
+ const id = `${moduleId}.${match[1]}`.replace(/^\./, "");
15
+ classes.push({ id, name: match[1], bases: (match[2] ?? "").split(",").map((item) => item.trim().split(".").pop()).filter(Boolean), moduleId });
16
+ }
17
+ }
18
+ const byName = new Map(classes.map((cls) => [cls.name, cls.id]));
19
+ const nodes = classes.map((cls) => ({ id: cls.id, label: cls.name, group: cls.moduleId }));
20
+ const edges = [];
21
+ for (const cls of classes) {
22
+ for (const base of cls.bases) {
23
+ if (byName.has(base)) edges.push({ source: cls.id, target: byName.get(base) });
24
+ }
25
+ }
26
+ return { direction: "TB", nodes, edges: reduceTransitive(nodes, edges) };
27
+ }
28
+
29
+ const args = parseArgs(process.argv.slice(2));
30
+ printOrWrite(`${JSON.stringify(scanPythonClasses(args._[0] ?? "."), null, 2)}\n`, args.output);
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parseArgs, printOrWrite, reduceTransitive, toPosix, walkFiles } from "./studio-core.mjs";
5
+
6
+ export function scanPythonModules(root) {
7
+ const absRoot = path.resolve(root);
8
+ const files = walkFiles(absRoot, (file) => file.endsWith(".py"));
9
+ const moduleByFile = new Map();
10
+ const nodes = files.map((file) => {
11
+ const rel = toPosix(path.relative(absRoot, file));
12
+ const id = rel.replace(/\/__init__\.py$/, "").replace(/\.py$/, "").replaceAll("/", ".");
13
+ moduleByFile.set(file, id || path.basename(absRoot));
14
+ return { id: id || path.basename(absRoot), label: path.basename(id || absRoot), group: id.includes(".") ? id.split(".").slice(0, -1).join(".") : undefined };
15
+ });
16
+ const ids = new Set(nodes.map((node) => node.id));
17
+ const edges = [];
18
+ for (const file of files) {
19
+ const source = moduleByFile.get(file);
20
+ const text = fs.readFileSync(file, "utf8");
21
+ for (const line of text.split(/\r?\n/)) {
22
+ const importMatch = line.match(/^\s*import\s+(.+)/);
23
+ if (importMatch) {
24
+ for (const item of importMatch[1].split(",")) addEdge(source, item.trim().split(/\s+as\s+/)[0], ids, edges);
25
+ }
26
+ const fromMatch = line.match(/^\s*from\s+([.\w]+)\s+import\s+(.+)/);
27
+ if (fromMatch) addEdge(source, resolveFromImport(source, fromMatch[1]), ids, edges);
28
+ }
29
+ }
30
+ return { direction: "LR", nodes, edges: reduceTransitive(nodes, edges) };
31
+ }
32
+
33
+ function addEdge(source, target, ids, edges) {
34
+ if (!target) return;
35
+ const parts = target.split(".");
36
+ while (parts.length) {
37
+ const candidate = parts.join(".");
38
+ if (ids.has(candidate)) {
39
+ edges.push({ source, target: candidate });
40
+ return;
41
+ }
42
+ parts.pop();
43
+ }
44
+ }
45
+
46
+ function resolveFromImport(source, spec) {
47
+ if (!spec.startsWith(".")) return spec;
48
+ const dots = spec.match(/^\.+/)?.[0].length ?? 0;
49
+ const suffix = spec.slice(dots);
50
+ const base = source.split(".").slice(0, Math.max(0, source.split(".").length - dots));
51
+ return [...base, suffix].filter(Boolean).join(".");
52
+ }
53
+
54
+ const args = parseArgs(process.argv.slice(2));
55
+ printOrWrite(`${JSON.stringify(scanPythonModules(args._[0] ?? "."), null, 2)}\n`, args.output);
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parseArgs, printOrWrite, reduceTransitive, toPosix, walkFiles } from "./studio-core.mjs";
5
+
6
+ export function scanRustModules(root) {
7
+ const srcRoot = fs.existsSync(path.join(root, "src")) ? path.join(root, "src") : root;
8
+ const absRoot = path.resolve(srcRoot);
9
+ const files = walkFiles(absRoot, (file) => file.endsWith(".rs"));
10
+ const fileToId = new Map();
11
+ const nodes = files.map((file) => {
12
+ let id = toPosix(path.relative(absRoot, file)).replace(/\.rs$/, "").replace(/\/mod$/, "").replace(/^(lib|main)$/, "crate").replaceAll("/", "::");
13
+ fileToId.set(file, id);
14
+ return { id, label: id.split("::").pop(), group: id.includes("::") ? id.split("::").slice(0, -1).join("::") : undefined };
15
+ });
16
+ const ids = new Set(nodes.map((node) => node.id));
17
+ const edges = [];
18
+ for (const file of files) {
19
+ const source = fileToId.get(file);
20
+ const text = fs.readFileSync(file, "utf8");
21
+ for (const match of text.matchAll(/\buse\s+(crate|self|super)::([^;{]+)[;{]/g)) {
22
+ const target = match[2].split("::").filter(Boolean)[0];
23
+ const candidates = [...ids].filter((id) => id === target || id.endsWith(`::${target}`));
24
+ if (candidates[0]) edges.push({ source, target: candidates[0] });
25
+ }
26
+ for (const match of text.matchAll(/\bmod\s+([A-Za-z_]\w*)\s*;/g)) {
27
+ const candidates = [...ids].filter((id) => id === match[1] || id.endsWith(`::${match[1]}`));
28
+ if (candidates[0]) edges.push({ source, target: candidates[0] });
29
+ }
30
+ }
31
+ return { direction: "LR", nodes, edges: reduceTransitive(nodes, edges) };
32
+ }
33
+
34
+ const args = parseArgs(process.argv.slice(2));
35
+ printOrWrite(`${JSON.stringify(scanRustModules(args._[0] ?? "."), null, 2)}\n`, args.output);
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs, printOrWrite } from "./studio-core.mjs";
3
+ import { scanModules } from "./scan-js-modules.mjs";
4
+
5
+ const args = parseArgs(process.argv.slice(2));
6
+ const graph = scanModules(args._[0] ?? ".", [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
7
+ printOrWrite(`${JSON.stringify(graph, null, 2)}\n`, args.output);