framework-m-studio 0.10.2__tar.gz → 0.12.0__tar.gz

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 (305) hide show
  1. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/CHANGELOG.md +24 -0
  2. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/PKG-INFO +3 -3
  3. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/pyproject.toml +7 -11
  4. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/__init__.py +11 -2
  5. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/app.py +81 -5
  6. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/deps.py +12 -12
  7. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/dev.py +6 -6
  8. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/new.py +3 -3
  9. framework_m_studio-0.12.0/src/framework_m_studio/cli/release/lockfile_sync.py +41 -0
  10. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/orchestrator.py +9 -35
  11. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/__init__.py +2 -4
  12. framework_m_studio-0.12.0/src/framework_m_studio/codegen/annotation_parser.py +104 -0
  13. framework_m_studio-0.12.0/src/framework_m_studio/codegen/generator.py +184 -0
  14. framework_m_studio-0.12.0/src/framework_m_studio/codegen/meta_extractor.py +54 -0
  15. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/parser.py +78 -256
  16. framework_m_studio-0.12.0/src/framework_m_studio/codegen/templates/__init__.py.jinja2 +9 -0
  17. framework_m_studio-0.12.0/src/framework_m_studio/codegen/templates/controller.py.jinja2 +63 -0
  18. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/templates/doctype.py.jinja2 +7 -9
  19. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/templates/test_doctype.py.jinja2 +4 -4
  20. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/test_generator.py +3 -1
  21. framework_m_studio-0.12.0/src/framework_m_studio/core/adapters/cst/mutator.py +96 -0
  22. framework_m_studio-0.12.0/src/framework_m_studio/core/codegen/augmentation_gen.py +68 -0
  23. framework_m_studio-0.12.0/src/framework_m_studio/core/discovery/pydantic.py +56 -0
  24. framework_m_studio-0.12.0/src/framework_m_studio/core/discovery/roles.py +59 -0
  25. framework_m_studio-0.12.0/src/framework_m_studio/core/repositories/fs_mx_repo.py +111 -0
  26. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/data_elements.py +10 -0
  27. framework_m_studio-0.12.0/src/framework_m_studio/dev_config.py +259 -0
  28. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/__init__.py +9 -0
  29. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/controller.py +29 -0
  30. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_doc_type/doctype.py +44 -0
  31. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/__init__.py +9 -0
  32. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/controller.py +29 -0
  33. framework_m_studio-0.12.0/src/framework_m_studio/doctypes/virtual_field/doctype.py +46 -0
  34. framework_m_studio-0.12.0/src/framework_m_studio/resources/blueprints/standard.json +60 -0
  35. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/crm.json +21 -0
  36. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/financial.json +21 -0
  37. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/hr.json +21 -0
  38. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/inventory.json +21 -0
  39. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/project.json +13 -0
  40. framework_m_studio-0.12.0/src/framework_m_studio/resources/roles/standard.json +17 -0
  41. framework_m_studio-0.12.0/src/framework_m_studio/routers/__init__.py +1 -0
  42. framework_m_studio-0.12.0/src/framework_m_studio/routers/aggregate.py +55 -0
  43. framework_m_studio-0.12.0/src/framework_m_studio/routers/doctypes.py +129 -0
  44. framework_m_studio-0.12.0/src/framework_m_studio/routers/print.py +74 -0
  45. framework_m_studio-0.12.0/src/framework_m_studio/routers/publish.py +104 -0
  46. framework_m_studio-0.12.0/src/framework_m_studio/routers/roles.py +20 -0
  47. framework_m_studio-0.12.0/src/framework_m_studio/routers/shell.py +56 -0
  48. framework_m_studio-0.12.0/src/framework_m_studio/routes.py +28 -0
  49. framework_m_studio-0.12.0/src/framework_m_studio/schemas.py +227 -0
  50. framework_m_studio-0.12.0/src/framework_m_studio/services/__init__.py +0 -0
  51. framework_m_studio-0.12.0/src/framework_m_studio/services/aggregate.py +38 -0
  52. framework_m_studio-0.12.0/src/framework_m_studio/services/doctype.py +153 -0
  53. framework_m_studio-0.12.0/src/framework_m_studio/services/print_service.py +58 -0
  54. framework_m_studio-0.12.0/src/framework_m_studio/services/publish.py +48 -0
  55. framework_m_studio-0.12.0/src/framework_m_studio/services/shell.py +72 -0
  56. framework_m_studio-0.12.0/src/framework_m_studio/services/workspace.py +53 -0
  57. framework_m_studio-0.12.0/src/framework_m_studio/static/.gitkeep +0 -0
  58. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/browser-ponyfill-DY7R_jX1.js +2 -0
  59. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/index-1KLiXoy5.js +124 -0
  60. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/index-DymRru6K.css +1 -0
  61. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-icons-C9MKFQpH.js +1 -0
  62. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-react-C1jOJk9g.js +59 -0
  63. framework_m_studio-0.12.0/src/framework_m_studio/static/assets/vendor-tamagui-BwPfGmbG.js +26 -0
  64. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/static/index.html +6 -14
  65. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/README.md.template +1 -1
  66. framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +69 -0
  67. framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/favicon.png +0 -0
  68. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/index.tsx.template +4 -12
  69. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/package.json.template +5 -4
  70. framework_m_studio-0.12.0/src/framework_m_studio/templates/plugin/plugin.config.ts.template +55 -0
  71. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/vite.config.ts.template +47 -1
  72. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/CHANGELOG.md +7 -0
  73. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/index.html +2 -12
  74. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/package.json +17 -15
  75. framework_m_studio-0.12.0/studio_ui/public/favicon.png +0 -0
  76. framework_m_studio-0.12.0/studio_ui/src/App.test.tsx +27 -0
  77. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/App.tsx +6 -24
  78. framework_m_studio-0.12.0/studio_ui/src/components/AggregateTab.test.tsx +42 -0
  79. framework_m_studio-0.12.0/studio_ui/src/components/AggregateTab.tsx +127 -0
  80. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/CodePreview.tsx +1 -1
  81. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/FieldEditor.tsx +46 -24
  82. framework_m_studio-0.12.0/studio_ui/src/components/MetaEditor.test.tsx +57 -0
  83. framework_m_studio-0.12.0/studio_ui/src/components/MetaEditor.tsx +257 -0
  84. framework_m_studio-0.12.0/studio_ui/src/components/MigrationTab.test.tsx +59 -0
  85. framework_m_studio-0.12.0/studio_ui/src/components/MigrationTab.tsx +117 -0
  86. framework_m_studio-0.12.0/studio_ui/src/components/PrintTab.test.tsx +49 -0
  87. framework_m_studio-0.12.0/studio_ui/src/components/PrintTab.tsx +226 -0
  88. framework_m_studio-0.12.0/studio_ui/src/components/PropertiesPanel.tsx +361 -0
  89. framework_m_studio-0.12.0/studio_ui/src/designer/DesignerCanvas.test.tsx +94 -0
  90. framework_m_studio-0.12.0/studio_ui/src/designer/DesignerCanvas.tsx +358 -0
  91. framework_m_studio-0.12.0/studio_ui/src/designer/components/PaletteItem.tsx +30 -0
  92. framework_m_studio-0.12.0/studio_ui/src/designer/components/SectionDropZone.tsx +18 -0
  93. framework_m_studio-0.12.0/studio_ui/src/designer/hooks/useDesignerState.ts +201 -0
  94. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/index.css +1 -1
  95. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/edit.tsx +252 -396
  96. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/list.tsx +39 -20
  97. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/index.ts +0 -1
  98. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/data.ts +22 -25
  99. framework_m_studio-0.12.0/studio_ui/vite.config.ts +74 -0
  100. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/vitest.config.ts +5 -1
  101. framework_m_studio-0.12.0/tests/codegen/test_annotation_parser.py +66 -0
  102. framework_m_studio-0.12.0/tests/codegen/test_meta_extractor.py +59 -0
  103. framework_m_studio-0.12.0/tests/core/adapters/test_cst_mutator.py +96 -0
  104. framework_m_studio-0.12.0/tests/core/codegen/test_augmentation_gen.py +31 -0
  105. framework_m_studio-0.12.0/tests/core/discovery/test_pydantic_discovery.py +51 -0
  106. framework_m_studio-0.12.0/tests/core/discovery/test_role_discovery.py +43 -0
  107. framework_m_studio-0.12.0/tests/core/repositories/test_fs_mx_repo.py +111 -0
  108. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_shell.py +40 -0
  109. framework_m_studio-0.12.0/tests/doctypes/virtual_doc_type/test_virtual_doc_type.py +21 -0
  110. framework_m_studio-0.12.0/tests/doctypes/virtual_field/test_virtual_field.py +21 -0
  111. framework_m_studio-0.12.0/tests/test_aggregate_builder_branches.py +15 -0
  112. framework_m_studio-0.12.0/tests/test_aggregate_generator.py +57 -0
  113. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_api_routes.py +241 -29
  114. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_builder_shell_routes.py +11 -2
  115. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli.py +20 -0
  116. framework_m_studio-0.12.0/tests/test_codegen_cli.py +24 -0
  117. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_contrib_cli.py +33 -0
  118. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_deps_cli.py +100 -0
  119. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_dev_cli_coverage.py +103 -0
  120. framework_m_studio-0.12.0/tests/test_dev_config.py +428 -0
  121. framework_m_studio-0.12.0/tests/test_docs_generator_extended.py +245 -0
  122. framework_m_studio-0.12.0/tests/test_doctype_service_coverage.py +152 -0
  123. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_generator.py +8 -91
  124. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_git_adapter.py +139 -0
  125. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_github_provider.py +54 -0
  126. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_live_preview.py +17 -0
  127. framework_m_studio-0.12.0/tests/test_lockfile_sync.py +79 -0
  128. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_new_cli.py +4 -3
  129. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_parser.py +220 -63
  130. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_print_adapter.py +41 -1
  131. framework_m_studio-0.12.0/tests/test_print_router_isolated.py +30 -0
  132. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_quality_cli.py +117 -0
  133. framework_m_studio-0.12.0/tests/test_release_orchestrator.py +528 -0
  134. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_routes_extended.py +86 -39
  135. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_schema_diff.py +52 -0
  136. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_studio_codegen_generator.py +2 -2
  137. framework_m_studio-0.12.0/tests/test_studio_init.py +19 -0
  138. framework_m_studio-0.12.0/tests/test_transformer.py +304 -0
  139. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_uimeta_routes.py +1 -1
  140. framework_m_studio-0.12.0/tests/test_workspace_coverage.py +72 -0
  141. framework_m_studio-0.10.2/src/framework_m_studio/codegen/generator.py +0 -295
  142. framework_m_studio-0.10.2/src/framework_m_studio/routes.py +0 -1326
  143. framework_m_studio-0.10.2/src/framework_m_studio/static/assets/index-BA2TojqY.css +0 -1
  144. framework_m_studio-0.10.2/src/framework_m_studio/static/assets/index-Db96rZJC.js +0 -182
  145. framework_m_studio-0.10.2/src/framework_m_studio/static/favicon.ico +0 -0
  146. framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +0 -129
  147. framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin/plugin.config.ts.template +0 -31
  148. framework_m_studio-0.10.2/studio_ui/public/favicon.ico +0 -0
  149. framework_m_studio-0.10.2/studio_ui/src/App.test.tsx +0 -16
  150. framework_m_studio-0.10.2/studio_ui/src/pages/aggregates/AggregateBuilderPage.tsx +0 -254
  151. framework_m_studio-0.10.2/studio_ui/src/pages/aggregates/index.ts +0 -1
  152. framework_m_studio-0.10.2/studio_ui/vite.config.ts +0 -21
  153. framework_m_studio-0.10.2/tests/test_docs_generator_extended.py +0 -77
  154. framework_m_studio-0.10.2/tests/test_release_orchestrator.py +0 -233
  155. framework_m_studio-0.10.2/tests/test_transformer.py +0 -176
  156. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/.gitignore +0 -0
  157. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/LICENSE +0 -0
  158. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/README.md +0 -0
  159. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/docs/api/index.md +0 -0
  160. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/docs/user-guide.md +0 -0
  161. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/aggregate_builder.py +0 -0
  162. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/__init__.py +0 -0
  163. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/codegen.py +0 -0
  164. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/constants.py +0 -0
  165. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/contrib.py +0 -0
  166. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/docs.py +0 -0
  167. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/quality.py +0 -0
  168. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/__init__.py +0 -0
  169. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/cli.py +0 -0
  170. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/gitops.py +0 -0
  171. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/graph.py +0 -0
  172. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/models.py +0 -0
  173. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/release/versioning.py +0 -0
  174. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/studio.py +0 -0
  175. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/utility.py +0 -0
  176. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/cli/verify.py +0 -0
  177. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/codegen/transformer.py +0 -0
  178. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/frontend.py +0 -0
  179. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/gitops.py +0 -0
  180. /framework_m_studio-0.10.2/src/framework_m_studio/py.typed → /framework_m_studio-0.12.0/src/framework_m_studio/core/repositories/git_mx_repo.py +0 -0
  181. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/core/shell.py +0 -0
  182. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/discovery.py +0 -0
  183. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/ast_parsers.py +0 -0
  184. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/audit.py +0 -0
  185. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/exporters.py +0 -0
  186. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/formatters.py +0 -0
  187. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/generator.py +0 -0
  188. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/docs/openapi.py +0 -0
  189. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/ephemeral.py +0 -0
  190. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/__init__.py +0 -0
  191. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/adapter.py +0 -0
  192. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/github_provider.py +0 -0
  193. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/git/protocol.py +0 -0
  194. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/guardrail.py +0 -0
  195. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/live_preview.py +0 -0
  196. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/metadata_editor.py +0 -0
  197. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/print_adapter.py +0 -0
  198. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/protocol_scanner.py +0 -0
  199. /framework_m_studio-0.10.2/src/framework_m_studio/static/.gitkeep → /framework_m_studio-0.12.0/src/framework_m_studio/py.typed +0 -0
  200. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/schema_diff.py +0 -0
  201. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/sdk_generator.py +0 -0
  202. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/shell_plugin_config.py +0 -0
  203. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/sidebar_config.py +0 -0
  204. {framework_m_studio-0.10.2/src/framework_m_studio/templates/plugin → framework_m_studio-0.12.0/src/framework_m_studio/static}/favicon.png +0 -0
  205. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/__init__.py +0 -0
  206. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/file_adapter.py +0 -0
  207. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/git_api_adapter.py +0 -0
  208. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/storage/protocol.py +0 -0
  209. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/__init__.py.template +0 -0
  210. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/doctypes_init.py.template +0 -0
  211. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/app/pyproject.toml.template +0 -0
  212. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/__init__.py.template +0 -0
  213. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/controller.py.template +0 -0
  214. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/doctype.py.template +0 -0
  215. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/doctype/test.py.template +0 -0
  216. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/.gitignore.template +0 -0
  217. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/README.md.template +0 -0
  218. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/index.html.template +0 -0
  219. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/theme.css.template +0 -0
  220. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/tsconfig.json.template +0 -0
  221. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/templates/plugin/vite.config.mfe.ts.template +0 -0
  222. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/visual_designer.py +0 -0
  223. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/src/framework_m_studio/workspace.py +0 -0
  224. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/.gitignore +0 -0
  225. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/.npmrc +0 -0
  226. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/Dockerfile +0 -0
  227. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/README.md +0 -0
  228. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/eslint.config.js +0 -0
  229. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/pnpm-lock.yaml +0 -0
  230. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/App.css +0 -0
  231. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/AutoForm.tsx +0 -0
  232. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/AutoTable.tsx +0 -0
  233. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ControllerEditor.tsx +0 -0
  234. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ERDView.tsx +0 -0
  235. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/LayoutDesigner.tsx +0 -0
  236. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/ModuleExplorer.tsx +0 -0
  237. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/NestedEditorDrawer.tsx +0 -0
  238. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/SandboxPreview.tsx +0 -0
  239. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/TableFieldEditor.tsx +0 -0
  240. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/breadcrumb/index.tsx +0 -0
  241. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/DefaultFieldComponents.tsx +0 -0
  242. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/index.ts +0 -0
  243. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/fields/resolveFieldComponent.ts +0 -0
  244. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/layout/index.tsx +0 -0
  245. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/components/menu/index.tsx +0 -0
  246. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/index.tsx +0 -0
  247. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/doctypes/index.ts +0 -0
  248. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/prints/PrintBuilderPage.tsx +0 -0
  249. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/prints/index.ts +0 -0
  250. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/shell-config/ShellConfiguratorPage.tsx +0 -0
  251. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/pages/shell-config/index.ts +0 -0
  252. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/ThemeContext.ts +0 -0
  253. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/constants.ts +0 -0
  254. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/theme.tsx +0 -0
  255. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/providers/useTheme.ts +0 -0
  256. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/defaultComponents.ts +0 -0
  257. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/fieldComponents.ts +0 -0
  258. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/registry/index.ts +0 -0
  259. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/services/mock_data.ts +0 -0
  260. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/setupTests.ts +0 -0
  261. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/utils/mockDataGenerator.ts +0 -0
  262. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/src/vite-env.d.ts +0 -0
  263. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/tsconfig.json +0 -0
  264. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/studio_ui/tsconfig.node.json +0 -0
  265. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/cli/test_new.py +0 -0
  266. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/cli/test_verify.py +0 -0
  267. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/conftest.py +0 -0
  268. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_frontend.py +0 -0
  269. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/core/test_gitops.py +0 -0
  270. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_aggregate_builder.py +0 -0
  271. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli_openapi.py +0 -0
  272. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_cli_utility.py +0 -0
  273. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_core_frontend.py +0 -0
  274. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_data_elements.py +0 -0
  275. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_data_elements_extended.py +0 -0
  276. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_dev.py +0 -0
  277. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_discovery.py +0 -0
  278. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_ast_parsers.py +0 -0
  279. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_audit.py +0 -0
  280. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_exporters.py +0 -0
  281. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_generator.py +0 -0
  282. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_docs_generator_enhanced.py +0 -0
  283. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_ephemeral.py +0 -0
  284. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_frontend_integration.py +0 -0
  285. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_git_protocol.py +0 -0
  286. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_guardrail.py +0 -0
  287. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_metadata_editor.py +0 -0
  288. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_multi_repo_workspace.py +0 -0
  289. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_protocol_scanner.py +0 -0
  290. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_protocol_scanner_extended.py +0 -0
  291. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_cli.py +0 -0
  292. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_cli_more.py +0 -0
  293. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_gitops.py +0 -0
  294. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_graph.py +0 -0
  295. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_release_versioning.py +0 -0
  296. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_screenshot_pipeline.py +0 -0
  297. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_sdk_generator.py +0 -0
  298. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_shell_plugin_config.py +0 -0
  299. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_sidebar_routes.py +0 -0
  300. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_storage_adapters.py +0 -0
  301. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_studio.py +0 -0
  302. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_utility_cli.py +0 -0
  303. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_utility_cli_enhanced.py +0 -0
  304. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_visual_designer.py +0 -0
  305. {framework_m_studio-0.10.2 → framework_m_studio-0.12.0}/tests/test_workspace.py +0 -0
@@ -1,3 +1,27 @@
1
+ ## framework-m-studio v0.12.0
2
+
3
+ ### Features
4
+
5
+ - update plugin scaffolding templates for navigation (83d7e7a)
6
+ - refactor aggregate builder into editor tab (2e1315c)
7
+ - implement aggregate controller generation (7bb53a1)
8
+ - migrate dev configurator and enhance doctype management (d8c2589)
9
+ - implement aggregate designer and codegen locking (160ca87)
10
+ - refactor API to modular routers and add role discovery (b0a37fa)
11
+ - implement code-first MX repositories and AST tools (635da9a)
12
+
13
+ ### Bug Fixes
14
+
15
+ - delete aggregate page related exports (dbdd28d)
16
+ - lint backend and frontend (170d500)
17
+ - build error for edit.tsx (36e791b)
18
+
19
+ ## framework-m-studio v0.11.0
20
+
21
+ ### Features
22
+
23
+ - update scaffolding templates for virtual modules and vite dedupe (6e20d30)
24
+
1
25
  ## framework-m-studio v0.10.2
2
26
 
3
27
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: framework-m-studio
3
- Version: 0.10.2
3
+ Version: 0.12.0
4
4
  Summary: Framework M Studio - Visual DocType Builder & Developer Tools
5
5
  Project-URL: Homepage, https://gitlab.com/castlecraft/framework-m
6
6
  Project-URL: Documentation, https://gitlab.com/castlecraft/framework-m#readme
@@ -20,8 +20,8 @@ Classifier: Typing :: Typed
20
20
  Requires-Python: >=3.12
21
21
  Requires-Dist: bandit>=1.9.4
22
22
  Requires-Dist: build>=1.0.0
23
- Requires-Dist: framework-m-core>=0.12.0
24
- Requires-Dist: framework-m>=0.7.2
23
+ Requires-Dist: framework-m-core>=0.14.0
24
+ Requires-Dist: framework-m>=0.8.0
25
25
  Requires-Dist: honcho>=1.1.0
26
26
  Requires-Dist: httpx>=0.27.0
27
27
  Requires-Dist: ipython>=9.11.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "framework-m-studio"
3
- version = "0.10.2"
3
+ version = "0.12.0"
4
4
  description = "Framework M Studio - Visual DocType Builder & Developer Tools"
5
5
  readme = "README.md"
6
6
  license = { text = "Apache-2.0" }
@@ -21,8 +21,8 @@ classifiers = [
21
21
  ]
22
22
 
23
23
  dependencies = [
24
- "framework-m-core>=0.12.0",
25
- "framework-m>=0.7.2",
24
+ "framework-m-core>=0.14.0",
25
+ "framework-m>=0.8.0",
26
26
  # Code generation
27
27
  "libcst>=1.0.0",
28
28
  "jinja2>=3.1.0",
@@ -125,6 +125,10 @@ filterwarnings = [
125
125
  [tool.coverage.run]
126
126
  source = ["src/framework_m_studio"]
127
127
  branch = true
128
+ omit = [
129
+ "*/tests/*",
130
+ "*conftest.py",
131
+ ]
128
132
 
129
133
  [tool.mypy]
130
134
  python_version = "3.12"
@@ -140,14 +144,6 @@ exclude = [
140
144
  "src/doctypes/",
141
145
  ]
142
146
 
143
- [[tool.mypy.overrides]]
144
- module = "framework_m.core.fields.registry"
145
- ignore_missing_imports = true
146
-
147
- [[tool.mypy.overrides]]
148
- module = "honcho.*"
149
- ignore_missing_imports = true
150
-
151
147
  [[tool.mypy.overrides]]
152
148
  module = "yaml"
153
149
  ignore_missing_imports = true
@@ -16,6 +16,15 @@ import importlib.metadata
16
16
  try:
17
17
  __version__ = importlib.metadata.version("framework-m-studio")
18
18
  except importlib.metadata.PackageNotFoundError:
19
- __version__ = "0.0.0"
19
+ __version__ = "0.0.0" # pragma: no cover
20
20
 
21
- __all__ = ["__version__"]
21
+ app = {
22
+ "name": "framework-m-studio",
23
+ "version": __version__,
24
+ "title": "Studio",
25
+ "description": "Visual DocType Builder & Developer Tools",
26
+ "color": "#8B5CF6",
27
+ "icon": "Paintbrush",
28
+ }
29
+
30
+ __all__ = ["__version__", "app"]
@@ -10,6 +10,7 @@ Usage:
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import os
13
14
  from pathlib import Path
14
15
  from typing import Any
15
16
 
@@ -18,7 +19,7 @@ from litestar.config.cors import CORSConfig
18
19
  from litestar.response import File, Redirect
19
20
  from litestar.static_files import create_static_files_router
20
21
 
21
- from framework_m_studio.routes import DocTypeController
22
+ from framework_m_studio.routes import api_router
22
23
 
23
24
  # Path to static files (built React app)
24
25
  STATIC_DIR = Path(__file__).parent / "static"
@@ -172,6 +173,8 @@ async def list_field_types() -> dict[str, Any]:
172
173
  try:
173
174
  from framework_m_standard.adapters.db.field_registry import FieldRegistry
174
175
 
176
+ from framework_m_studio.data_elements import DataElementRegistry
177
+
175
178
  types_list = []
176
179
  for type_info in FieldRegistry.get_instance().get_all_types():
177
180
  types_list.append(
@@ -184,8 +187,81 @@ async def list_field_types() -> dict[str, Any]:
184
187
  "validators": type_info.validators,
185
188
  }
186
189
  )
187
- return {"field_types": types_list}
188
- except ImportError:
190
+
191
+ # Load Blueprints (Data Elements)
192
+ element_registry = DataElementRegistry()
193
+
194
+ # 1. Load OOTB blueprints from Studio resources
195
+ studio_blueprints_dir = Path(__file__).parent / "resources" / "blueprints"
196
+ if studio_blueprints_dir.exists():
197
+ for p in studio_blueprints_dir.glob("*.json"):
198
+ element_registry = DataElementRegistry.merge(
199
+ element_registry, DataElementRegistry.from_json(p)
200
+ )
201
+
202
+ # 2. Load domain-specific blueprints from installed apps
203
+ import importlib.util
204
+ from importlib.metadata import entry_points
205
+
206
+ installed_apps = [
207
+ a.strip()
208
+ for a in os.environ.get("INSTALLED_APPS", "").split(",")
209
+ if a.strip()
210
+ ]
211
+ for ep in entry_points(group="framework_m.apps"):
212
+ app_module = ep.module.split(":")[0]
213
+ if app_module not in installed_apps:
214
+ installed_apps.append(app_module)
215
+
216
+ for app_name in installed_apps:
217
+ spec = importlib.util.find_spec(app_name)
218
+ if spec and spec.origin:
219
+ app_blueprints_dir = (
220
+ Path(spec.origin).parent / "resources" / "blueprints"
221
+ )
222
+ if app_blueprints_dir.exists(): # pragma: no cover
223
+ for p in app_blueprints_dir.glob("*.json"): # pragma: no cover
224
+ element_registry = DataElementRegistry.merge(
225
+ element_registry, DataElementRegistry.from_json(p)
226
+ )
227
+
228
+ # 3. Load custom blueprints from project root
229
+ project_blueprints_dir = Path.cwd() / "blueprints"
230
+ if project_blueprints_dir.exists(): # pragma: no cover
231
+ for p in project_blueprints_dir.glob("*.json"): # pragma: no cover
232
+ element_registry = DataElementRegistry.merge(
233
+ element_registry, DataElementRegistry.from_json(p)
234
+ ) # pragma: no cover
235
+
236
+ blueprint_list = []
237
+ for elem in element_registry.elements.values():
238
+ # Find base type to inherit ui_widget and pydantic_type
239
+ base_type = next(
240
+ (t for t in types_list if t["name"] == elem.fieldtype), None
241
+ )
242
+ ui_widget = base_type["ui_widget"] if base_type else "text"
243
+ pydantic_type = base_type["pydantic_type"] if base_type else "str"
244
+
245
+ validators: dict[str, Any] = {}
246
+ if elem.validation:
247
+ validators["pattern"] = elem.validation
248
+ if elem.length:
249
+ validators["max_length"] = elem.length
250
+
251
+ blueprint_list.append(
252
+ {
253
+ "name": elem.id,
254
+ "pydantic_type": pydantic_type,
255
+ "label": f"💎 {elem.label}", # Visual indicator for blueprints
256
+ "ui_widget": ui_widget,
257
+ "category": "blueprint",
258
+ "domain": elem.domain,
259
+ "validators": validators if validators else None,
260
+ }
261
+ )
262
+
263
+ return {"field_types": types_list + blueprint_list}
264
+ except ImportError: # pragma: no cover
189
265
  # Fallback to static list if framework_m not available
190
266
  return {
191
267
  "field_types": [
@@ -273,7 +349,7 @@ def create_app() -> Litestar:
273
349
  """Create the Studio Litestar application."""
274
350
  route_handlers: list[Any] = [
275
351
  studio_api_router,
276
- DocTypeController, # File System API for DocTypes
352
+ api_router, # All Domain API Routers
277
353
  ]
278
354
  # Always include favicon and redirects
279
355
  route_handlers.extend(
@@ -288,7 +364,7 @@ def create_app() -> Litestar:
288
364
  # and static assets.
289
365
 
290
366
  # Static assets (js/css/images)
291
- if STATIC_DIR.exists():
367
+ if STATIC_DIR.exists(): # pragma: no cover
292
368
  route_handlers.append(
293
369
  create_static_files_router(
294
370
  path="/studio/ui/assets",
@@ -49,8 +49,8 @@ def _check_pnpm_outdated(root: Path) -> list[dict[str, str]]:
49
49
  "latest": details.get("latest", ""),
50
50
  }
51
51
  )
52
- except json.JSONDecodeError:
53
- pass
52
+ except json.JSONDecodeError: # pragma: no cover
53
+ pass # pragma: no cover
54
54
  return outdated
55
55
 
56
56
 
@@ -104,8 +104,8 @@ def _get_workspace_projects(
104
104
  )
105
105
  projects.append(proj_name)
106
106
  break
107
- except Exception:
108
- pass
107
+ except Exception: # pragma: no cover
108
+ pass # pragma: no cover
109
109
  elif manager == "pnpm":
110
110
  pkg_json = item / "package.json"
111
111
  if pkg_json.exists():
@@ -123,8 +123,8 @@ def _get_workspace_projects(
123
123
  and "name" in data
124
124
  ):
125
125
  projects.append(data["name"])
126
- except Exception:
127
- pass
126
+ except Exception: # pragma: no cover
127
+ pass # pragma: no cover
128
128
  return sorted(set(projects))
129
129
 
130
130
 
@@ -243,18 +243,18 @@ async def deps_upgrade_command(
243
243
  run_cmd("pnpm update -r", cwd=root_path)
244
244
  print("Running pnpm audit fix...")
245
245
  run_cmd("pnpm audit fix", cwd=root_path, check=False)
246
- else:
247
- print(f"Unknown manager: {manager}", file=sys.stderr)
248
- return
246
+ else: # pragma: no cover
247
+ print(f"Unknown manager: {manager}", file=sys.stderr) # pragma: no cover
248
+ return # pragma: no cover
249
249
  package = "all"
250
250
  else:
251
251
  if manager == "uv":
252
252
  run_cmd(f"uv lock --upgrade-package {package}", cwd=root_path)
253
253
  elif manager == "pnpm":
254
254
  run_cmd(f"pnpm update -r {package}", cwd=root_path)
255
- else:
256
- print(f"Unknown manager: {manager}", file=sys.stderr)
257
- return
255
+ else: # pragma: no cover
256
+ print(f"Unknown manager: {manager}", file=sys.stderr) # pragma: no cover
257
+ return # pragma: no cover
258
258
 
259
259
  # Check if anything actually changed
260
260
  new_uv_mtime = uv_lock.stat().st_mtime if uv_lock.exists() else 0
@@ -38,12 +38,6 @@ from pathlib import Path
38
38
  from typing import Annotated, Any
39
39
 
40
40
  import cyclopts
41
- from framework_m_core.dev_config import (
42
- get_default_processes,
43
- load_dev_config_from_toml,
44
- load_procfile,
45
- merge_process_configs,
46
- )
47
41
 
48
42
  from framework_m_studio.cli.constants import (
49
43
  DEFAULT_BACKEND_PORT,
@@ -56,6 +50,12 @@ from framework_m_studio.core.frontend import (
56
50
  generate_plugin_entry,
57
51
  generate_vite_config,
58
52
  )
53
+ from framework_m_studio.dev_config import (
54
+ get_default_processes,
55
+ load_dev_config_from_toml,
56
+ load_procfile,
57
+ merge_process_configs,
58
+ )
59
59
 
60
60
 
61
61
  def _load_honcho_symbols() -> tuple[Any, Any]:
@@ -399,9 +399,9 @@ def new_doctype_command(
399
399
  - test_*.py (pytest tests)
400
400
 
401
401
  Examples:
402
- m new:doctype Invoice
403
- m new:doctype Invoice --app myapp
404
- m new:doctype SalesOrder --output ./my_doctypes/sales_order
402
+ m new doctype Invoice
403
+ m new doctype Invoice --app myapp
404
+ m new doctype SalesOrder --output ./my_doctypes/sales_order
405
405
  """
406
406
  # Detect app if not provided
407
407
  detected_app = detect_app(app)
@@ -0,0 +1,41 @@
1
+ """Lockfile synchronization utilities for release orchestration."""
2
+
3
+ import shutil
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ from framework_m_studio.core.shell import run_cmd
8
+
9
+
10
+ def sync_lockfiles(root: Path) -> None:
11
+ """Synchronize lockfiles for diverse environments."""
12
+ print("📦 Synchronizing lockfiles...")
13
+ if (root / "pnpm-lock.yaml").exists():
14
+ pnpm_bin = shutil.which("pnpm")
15
+ if pnpm_bin:
16
+ try:
17
+ run_cmd([pnpm_bin, "install", "--no-frozen-lockfile"], check=True)
18
+ except Exception as e:
19
+ print(f"Error: pnpm lockfile sync failed: {e}", file=sys.stderr)
20
+ raise
21
+ else:
22
+ raise RuntimeError(
23
+ "pnpm-lock.yaml exists but 'pnpm' tool was not found. "
24
+ "Please install pnpm or ensure it's in your PATH to synchronize lockfiles."
25
+ )
26
+
27
+ if (root / "uv.lock").exists() or (root / "pyproject.toml").exists():
28
+ uv_bin = shutil.which("uv")
29
+ if uv_bin:
30
+ try:
31
+ run_cmd([uv_bin, "lock"], check=True)
32
+ except Exception as e:
33
+ print(f"Error: uv lockfile sync failed: {e}", file=sys.stderr)
34
+ raise
35
+ else:
36
+ # Only fail on uv if we explicitly have a uv.lock or need to generate one
37
+ if (root / "uv.lock").exists():
38
+ raise RuntimeError(
39
+ "uv.lock exists but 'uv' tool was not found. "
40
+ "Please install uv or ensure it's in your PATH to synchronize lockfiles."
41
+ )
@@ -116,8 +116,8 @@ def compute_release_plan(config: ReleaseConfig, root: Path) -> list[ReleaseUpdat
116
116
  try:
117
117
  if tag_v > file_v:
118
118
  current_v = tag_v
119
- except Exception:
120
- pass
119
+ except Exception: # pragma: no cover
120
+ pass # pragma: no cover
121
121
 
122
122
  new_v = _bump_version(current_v, bump)
123
123
  changelog = _generate_changelog(component_commits, new_v, pkg.name)
@@ -133,7 +133,7 @@ def compute_release_plan(config: ReleaseConfig, root: Path) -> list[ReleaseUpdat
133
133
 
134
134
  # 1. Propagate bumps downstream through the dependency graph
135
135
  if not release_updates:
136
- return []
136
+ return [] # pragma: no cover
137
137
 
138
138
  graph = DependencyGraph(config, root)
139
139
  graph.discover_manifest_deps()
@@ -154,12 +154,14 @@ def prepare_release(
154
154
  if sbom:
155
155
  syft_bin = shutil.which("syft")
156
156
  if not syft_bin:
157
- print("Warning: 'syft' not found, skipping SBOM.", file=sys.stderr)
157
+ print(
158
+ "Warning: 'syft' not found, skipping SBOM.", file=sys.stderr
159
+ ) # pragma: no cover
158
160
  sbom = False
159
161
  else:
160
162
  try:
161
163
  run_cmd(f"syft scan dir:{root} -o json > {root}/sbom.json")
162
- except Exception:
164
+ except Exception: # pragma: no cover
163
165
  print("Warning: syft failed, skipping SBOM.", file=sys.stderr)
164
166
  sbom = False
165
167
 
@@ -201,37 +203,9 @@ def prepare_release(
201
203
  target_file.write_text(new_content)
202
204
 
203
205
  # 3. Synchronize lockfiles for diverse environments
204
- print("📦 Synchronizing lockfiles...")
205
- if (root / "pnpm-lock.yaml").exists():
206
- pnpm_bin = shutil.which("pnpm")
207
- if pnpm_bin:
208
- # We MUST succeed here to avoid CI frozen-lockfile mismatch
209
- try:
210
- run_cmd([pnpm_bin, "install", "--no-frozen-lockfile"], check=True)
211
- except Exception as e:
212
- print(f"Error: pnpm lockfile sync failed: {e}", file=sys.stderr)
213
- raise
214
- else:
215
- raise RuntimeError(
216
- "pnpm-lock.yaml exists but 'pnpm' tool was not found. "
217
- "Please install pnpm or ensure it's in your PATH to synchronize lockfiles."
218
- )
206
+ from .lockfile_sync import sync_lockfiles
219
207
 
220
- if (root / "uv.lock").exists() or (root / "pyproject.toml").exists():
221
- uv_bin = shutil.which("uv")
222
- if uv_bin:
223
- try:
224
- run_cmd([uv_bin, "lock"], check=True)
225
- except Exception as e:
226
- print(f"Error: uv lockfile sync failed: {e}", file=sys.stderr)
227
- raise
228
- else:
229
- # Only fail on uv if we explicitly have a uv.lock or need to generate one
230
- if (root / "uv.lock").exists():
231
- raise RuntimeError(
232
- "uv.lock exists but 'uv' tool was not found. "
233
- "Please install uv or ensure it's in your PATH to synchronize lockfiles."
234
- )
208
+ sync_lockfiles(root)
235
209
 
236
210
 
237
211
  async def create_or_update_mr(
@@ -9,12 +9,11 @@ This package provides:
9
9
 
10
10
  from framework_m_studio.codegen.generator import (
11
11
  generate_doctype_source,
12
- update_doctype_source,
13
12
  )
14
13
  from framework_m_studio.codegen.parser import (
15
- ConfigSchema,
16
14
  DocTypeSchema,
17
15
  FieldSchema,
16
+ MetaSchema,
18
17
  parse_doctype,
19
18
  )
20
19
  from framework_m_studio.codegen.test_generator import (
@@ -23,12 +22,11 @@ from framework_m_studio.codegen.test_generator import (
23
22
  )
24
23
 
25
24
  __all__ = [
26
- "ConfigSchema",
27
25
  "DocTypeSchema",
28
26
  "FieldSchema",
27
+ "MetaSchema",
29
28
  "generate_doctype_source",
30
29
  "generate_test",
31
30
  "generate_test_file",
32
31
  "parse_doctype",
33
- "update_doctype_source",
34
32
  ]
@@ -0,0 +1,104 @@
1
+ """Annotation Parser - Extracts field metadata from LibCST annotation nodes."""
2
+
3
+ from typing import Any
4
+
5
+ import libcst as cst
6
+
7
+
8
+ def node_to_source(node: cst.CSTNode) -> str:
9
+ """Convert CST node to source code string."""
10
+ return cst.Module(body=[]).code_for_node(node)
11
+
12
+
13
+ def extract_annotated_metadata(
14
+ type_node: cst.BaseExpression,
15
+ ) -> tuple[str | None, str | None, str]:
16
+ """Extract link_doctype, table_doctype, and base type from Annotated."""
17
+ field_type = node_to_source(type_node)
18
+
19
+ if isinstance(type_node, cst.BinaryOperation):
20
+ left_link, left_table, left_type = extract_annotated_metadata(type_node.left)
21
+ if left_link or left_table:
22
+ return left_link, left_table, left_type
23
+ right_link, right_table, right_type = extract_annotated_metadata(
24
+ type_node.right
25
+ )
26
+ return right_link, right_table, right_type
27
+
28
+ if isinstance(type_node, cst.Subscript):
29
+ subscript_value = node_to_source(type_node.value)
30
+ if subscript_value == "Annotated":
31
+ slice_elements = type_node.slice
32
+ if isinstance(slice_elements, tuple) and len(slice_elements) >= 1:
33
+ first_elem = slice_elements[0]
34
+ if isinstance(first_elem.slice, cst.Index):
35
+ base_type = node_to_source(first_elem.slice.value)
36
+ else:
37
+ base_type = node_to_source(first_elem.slice)
38
+
39
+ for elem in slice_elements[1:]:
40
+ value = (
41
+ elem.slice.value
42
+ if isinstance(elem.slice, cst.Index)
43
+ else elem.slice
44
+ )
45
+ if isinstance(value, cst.Call):
46
+ func_name = node_to_source(value.func)
47
+ if func_name == "Link" and value.args:
48
+ arg_value = node_to_source(value.args[0].value)
49
+ return arg_value.strip("\"'"), None, base_type
50
+ if func_name == "Table" and value.args:
51
+ arg_value = node_to_source(value.args[0].value)
52
+ return None, arg_value.strip("\"'"), base_type
53
+ return None, None, base_type
54
+
55
+ return None, None, field_type
56
+
57
+
58
+ def parse_field_call(
59
+ node: cst.Call,
60
+ ) -> tuple[str | None, dict[str, Any], str | None, str | None]:
61
+ """Parse Field(...) call and extract default, validators, description, and label."""
62
+ default_value: str | None = None
63
+ validators: dict[str, Any] = {}
64
+ description: str | None = None
65
+ label: str | None = None
66
+
67
+ for i, arg in enumerate(node.args):
68
+ if arg.keyword is None and i == 0:
69
+ default_value = node_to_source(arg.value)
70
+ continue
71
+
72
+ if isinstance(arg.keyword, cst.Name):
73
+ key = arg.keyword.value
74
+ value_str = node_to_source(arg.value)
75
+
76
+ if key == "ge":
77
+ val = float(value_str)
78
+ validators["min_value"] = int(val) if val == int(val) else val
79
+ elif key == "le":
80
+ val = float(value_str)
81
+ validators["max_value"] = int(val) if val == int(val) else val
82
+ elif key == "gt":
83
+ val = float(value_str)
84
+ validators["min_value"] = int(val) + 1 if val == int(val) else val
85
+ elif key == "lt":
86
+ val = float(value_str)
87
+ validators["max_value"] = int(val) - 1 if val == int(val) else val
88
+ elif key == "min_length":
89
+ validators["min_length"] = int(value_str)
90
+ elif key == "max_length":
91
+ validators["max_length"] = int(value_str)
92
+ elif key in ("pattern", "regex"):
93
+ pattern = value_str
94
+ if pattern.startswith("r"):
95
+ pattern = pattern[1:]
96
+ validators["pattern"] = pattern.strip("\"'")
97
+ elif key == "description":
98
+ description = value_str.strip("\"'")
99
+ elif key == "label":
100
+ label = value_str.strip("\"'")
101
+ elif key == "default":
102
+ default_value = value_str
103
+
104
+ return default_value, validators, description, label