framework-m-studio 0.8.4__tar.gz → 0.9.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.
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/.gitignore +2 -1
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/CHANGELOG.md +27 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/PKG-INFO +2 -2
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/pyproject.toml +2 -2
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/deps.py +108 -7
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/new.py +68 -226
- framework_m_studio-0.9.0/src/framework_m_studio/cli/release/graph.py +162 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/orchestrator.py +43 -14
- framework_m_studio-0.8.4/src/framework_m_studio/static/assets/index-C7HXLlUt.js → framework_m_studio-0.9.0/src/framework_m_studio/static/assets/index-DM0cHKco.js +2 -2
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/static/index.html +1 -1
- framework_m_studio-0.9.0/src/framework_m_studio/templates/app/README.md.template +36 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/app/__init__.py.template +11 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/app/doctypes_init.py.template +3 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/app/pyproject.toml.template +24 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/doctype/__init__.py.template +9 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/doctype/controller.py.template +26 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/doctype/doctype.py.template +38 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/doctype/test.py.template +23 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/.gitignore.template +63 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +52 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/favicon.png +0 -0
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/index.html → framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/index.html.template +6 -4
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/index.tsx.template +33 -0
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/package.json → framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/package.json.template +11 -4
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/theme.css.template +166 -0
- framework_m_studio-0.9.0/src/framework_m_studio/templates/plugin/vite.config.ts.template +20 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/package.json +5 -5
- framework_m_studio-0.9.0/studio_ui/public/favicon.ico +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/cli/test_new.py +15 -60
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_deps_cli.py +143 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_new_cli.py +2 -2
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_release_cli.py +58 -7
- framework_m_studio-0.9.0/tests/test_release_graph.py +180 -0
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/.gitignore +0 -32
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/.npmrc +0 -10
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/README.md +0 -85
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/App.tsx +0 -1088
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/components/AppNavbar.tsx +0 -233
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/components/AppSidebar.tsx +0 -173
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/index.tsx +0 -20
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/pages/LoginPage.tsx +0 -217
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/src/theme.css +0 -293
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/tsconfig.json +0 -19
- framework_m_studio-0.8.4/src/framework_m_studio/templates/frontend/vite.config.ts +0 -33
- framework_m_studio-0.8.4/src/framework_m_studio/templates/plugin/Dashboard.tsx.template +0 -10
- framework_m_studio-0.8.4/src/framework_m_studio/templates/plugin/package.json.template +0 -33
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/LICENSE +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/README.md +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/docs/api/index.md +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/docs/user-guide.md +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/__init__.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/app.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/__init__.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/codegen.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/constants.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/contrib.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/dev.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/docs.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/quality.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/__init__.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/cli.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/gitops.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/models.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/release/versioning.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/studio.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/utility.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/cli/verify.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/__init__.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/parser.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/templates/doctype.py.jinja2 +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/templates/test_doctype.py.jinja2 +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/test_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/codegen/transformer.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/core/frontend.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/core/gitops.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/core/shell.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/discovery.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/ast_parsers.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/audit.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/exporters.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/formatters.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/docs/openapi.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/git/__init__.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/git/adapter.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/git/github_provider.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/git/protocol.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/protocol_scanner.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/py.typed +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/routes.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/sdk_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/static/.gitkeep +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/static/assets/index-BXzUquLi.css +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/static/favicon.ico +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/templates/plugin/README.md.template +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/templates/plugin/plugin.config.ts.template +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/templates/plugin/tsconfig.json.template +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/templates/plugin/vite.config.mfe.ts.template +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/src/framework_m_studio/workspace.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/.gitignore +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/.npmrc +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/CHANGELOG.md +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/Dockerfile +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/README.md +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/eslint.config.js +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/index.html +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/pnpm-lock.yaml +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/App.css +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/App.test.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/App.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/AutoForm.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/AutoTable.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/CodePreview.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/ControllerEditor.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/ERDView.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/FieldEditor.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/LayoutDesigner.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/ModuleExplorer.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/NestedEditorDrawer.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/SandboxPreview.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/TableFieldEditor.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/breadcrumb/index.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/fields/DefaultFieldComponents.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/fields/index.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/fields/resolveFieldComponent.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/layout/index.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/components/menu/index.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/index.css +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/index.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/pages/doctypes/edit.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/pages/doctypes/index.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/pages/doctypes/list.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/pages/index.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/providers/ThemeContext.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/providers/constants.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/providers/data.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/providers/theme.tsx +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/providers/useTheme.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/registry/defaultComponents.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/registry/fieldComponents.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/registry/index.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/services/mock_data.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/setupTests.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/utils/mockDataGenerator.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/src/vite-env.d.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/tsconfig.json +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/tsconfig.node.json +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/vite.config.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/studio_ui/vitest.config.ts +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/cli/test_verify.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/conftest.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/core/test_frontend.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/core/test_gitops.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/core/test_shell.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_api_routes.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_cli.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_cli_openapi.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_contrib_cli.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_dev.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_dev_cli_coverage.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_discovery.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_docs_audit.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_docs_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_docs_generator_enhanced.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_frontend_integration.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_git_adapter.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_git_protocol.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_github_provider.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_parser.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_protocol_scanner.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_quality_cli.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_screenshot_pipeline.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_sdk_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_studio.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_studio_codegen_generator.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_transformer.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_utility_cli.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_utility_cli_enhanced.py +0 -0
- {framework_m_studio-0.8.4 → framework_m_studio-0.9.0}/tests/test_workspace.py +0 -0
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
## framework-m-studio v0.9.0
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- update plugin scaffolding for refined shell architecture (3dbc0f6)
|
|
6
|
+
- consolidate frontend scaffolding into unified plugin templates (c12ae9a)
|
|
7
|
+
- consolidated and externalized CLI scaffolding (f5633b2)
|
|
8
|
+
- update plugin scaffolding for refined shell architecture (96a23b0)
|
|
9
|
+
- consolidate frontend scaffolding into unified plugin templates (9f34e3a)
|
|
10
|
+
- consolidated and externalized CLI scaffolding (fae62f2)
|
|
11
|
+
- implement negative-filter discovery with regression tests (9305ad4)
|
|
12
|
+
- improve automated MR formatting (3168236)
|
|
13
|
+
- implement brand-aligned shell layout and improved frontend templates (7bf913e)
|
|
14
|
+
- automate dependency discovery for release (879bd49)
|
|
15
|
+
- add standalone landing page to plugin scaffold (4d9f834)
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
- robust dependency discovery and orchestrator compatibility (7def0e4)
|
|
20
|
+
- improve deps upgrade semantic commits and discovery (49f0f01)
|
|
21
|
+
|
|
22
|
+
## framework-m-studio v0.8.5
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
- add node types to tsconfig and sync related apps (da1934f)
|
|
27
|
+
|
|
1
28
|
## framework-m-studio v0.8.4
|
|
2
29
|
|
|
3
30
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: framework-m-studio
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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
|
|
@@ -21,7 +21,7 @@ Requires-Python: >=3.12
|
|
|
21
21
|
Requires-Dist: bandit>=1.9.4
|
|
22
22
|
Requires-Dist: build>=1.0.0
|
|
23
23
|
Requires-Dist: framework-m-core>=0.11.4
|
|
24
|
-
Requires-Dist: framework-m>=0.6.
|
|
24
|
+
Requires-Dist: framework-m>=0.6.9
|
|
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.
|
|
3
|
+
version = "0.9.0"
|
|
4
4
|
description = "Framework M Studio - Visual DocType Builder & Developer Tools"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
|
22
22
|
|
|
23
23
|
dependencies = [
|
|
24
24
|
"framework-m-core>=0.11.4",
|
|
25
|
-
"framework-m>=0.6.
|
|
25
|
+
"framework-m>=0.6.9",
|
|
26
26
|
# Code generation
|
|
27
27
|
"libcst>=1.0.0",
|
|
28
28
|
"jinja2>=3.1.0",
|
|
@@ -33,8 +33,8 @@ def _check_uv_outdated(root: Path) -> list[dict[str, str]]:
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def _check_pnpm_outdated(root: Path) -> list[dict[str, str]]:
|
|
36
|
-
"""Parse pnpm outdated --format json output."""
|
|
37
|
-
output = run_cmd("pnpm outdated --format json", cwd=root, check=False)
|
|
36
|
+
"""Parse pnpm outdated -r --format json output."""
|
|
37
|
+
output = run_cmd("pnpm outdated -r --format json", cwd=root, check=False)
|
|
38
38
|
outdated: list[dict[str, str]] = []
|
|
39
39
|
if not output:
|
|
40
40
|
return outdated
|
|
@@ -54,6 +54,80 @@ def _check_pnpm_outdated(root: Path) -> list[dict[str, str]]:
|
|
|
54
54
|
return outdated
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
def _get_workspace_projects(
|
|
58
|
+
root: Path,
|
|
59
|
+
manager: str,
|
|
60
|
+
base_dirs: list[str] | None = None,
|
|
61
|
+
updated_packages: list[str] | None = None,
|
|
62
|
+
) -> list[str]:
|
|
63
|
+
"""Get all workspace projects from the given base directories that depend on updated_packages."""
|
|
64
|
+
projects = []
|
|
65
|
+
|
|
66
|
+
# If no specific packages were updated, we can't easily filter
|
|
67
|
+
if not updated_packages:
|
|
68
|
+
return []
|
|
69
|
+
|
|
70
|
+
for base_dir in base_dirs or ["apps", "libs"]:
|
|
71
|
+
dir_path = root / base_dir
|
|
72
|
+
if not dir_path.exists():
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
for item in dir_path.iterdir():
|
|
76
|
+
if not item.is_dir() or item.name.startswith("."):
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
if manager == "uv":
|
|
80
|
+
pyproject = item / "pyproject.toml"
|
|
81
|
+
if pyproject.exists():
|
|
82
|
+
try:
|
|
83
|
+
content = pyproject.read_text()
|
|
84
|
+
# Check if this project depends on any of the updated packages
|
|
85
|
+
# We check for '"pkg-name"' or 'pkg-name>=' to avoid partial matches
|
|
86
|
+
has_dep = False
|
|
87
|
+
for pkg in updated_packages:
|
|
88
|
+
if (
|
|
89
|
+
f'"{pkg}"' in content
|
|
90
|
+
or f"'{pkg}'" in content
|
|
91
|
+
or f"{pkg}>=" in content
|
|
92
|
+
):
|
|
93
|
+
has_dep = True
|
|
94
|
+
break
|
|
95
|
+
|
|
96
|
+
if has_dep:
|
|
97
|
+
for line in content.splitlines():
|
|
98
|
+
if line.startswith("name ="):
|
|
99
|
+
proj_name = (
|
|
100
|
+
line.split("=", 1)[1]
|
|
101
|
+
.strip()
|
|
102
|
+
.strip('"')
|
|
103
|
+
.strip("'")
|
|
104
|
+
)
|
|
105
|
+
projects.append(proj_name)
|
|
106
|
+
break
|
|
107
|
+
except Exception:
|
|
108
|
+
pass
|
|
109
|
+
elif manager == "pnpm":
|
|
110
|
+
pkg_json = item / "package.json"
|
|
111
|
+
if pkg_json.exists():
|
|
112
|
+
try:
|
|
113
|
+
data = json.loads(pkg_json.read_text())
|
|
114
|
+
# Check all dependency types
|
|
115
|
+
all_deps = {
|
|
116
|
+
**data.get("dependencies", {}),
|
|
117
|
+
**data.get("devDependencies", {}),
|
|
118
|
+
**data.get("peerDependencies", {}),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
any(pkg in all_deps for pkg in updated_packages)
|
|
123
|
+
and "name" in data
|
|
124
|
+
):
|
|
125
|
+
projects.append(data["name"])
|
|
126
|
+
except Exception:
|
|
127
|
+
pass
|
|
128
|
+
return sorted(set(projects))
|
|
129
|
+
|
|
130
|
+
|
|
57
131
|
def _push_branch(branch: str, token: str) -> None:
|
|
58
132
|
"""Push branch to origin."""
|
|
59
133
|
host = os.environ.get("CI_SERVER_HOST", "gitlab.com")
|
|
@@ -123,6 +197,13 @@ async def deps_upgrade_command(
|
|
|
123
197
|
name="--skip-branch", help="Skip branch creation, keep changes unstaged"
|
|
124
198
|
),
|
|
125
199
|
] = False,
|
|
200
|
+
dirs: Annotated[
|
|
201
|
+
list[str] | None,
|
|
202
|
+
cyclopts.Parameter(
|
|
203
|
+
name="--dirs",
|
|
204
|
+
help="Base directories to discover workspace projects [default: apps libs]",
|
|
205
|
+
),
|
|
206
|
+
] = None,
|
|
126
207
|
) -> None:
|
|
127
208
|
"""Upgrade a dependency and create a merge request."""
|
|
128
209
|
root_path = Path(root) if root else Path.cwd()
|
|
@@ -141,6 +222,8 @@ async def deps_upgrade_command(
|
|
|
141
222
|
uv_mtime = uv_lock.stat().st_mtime if uv_lock.exists() else 0
|
|
142
223
|
pnpm_mtime = pnpm_lock.stat().st_mtime if pnpm_lock.exists() else 0
|
|
143
224
|
|
|
225
|
+
outdated: list[dict[str, str]] = []
|
|
226
|
+
|
|
144
227
|
if not package:
|
|
145
228
|
print(f"Checking for all outdated packages using {manager}...")
|
|
146
229
|
if manager == "uv":
|
|
@@ -156,6 +239,7 @@ async def deps_upgrade_command(
|
|
|
156
239
|
)
|
|
157
240
|
run_cmd(f"uv lock {pkg_args}", cwd=root_path)
|
|
158
241
|
elif manager == "pnpm":
|
|
242
|
+
outdated = _check_pnpm_outdated(root_path)
|
|
159
243
|
run_cmd("pnpm update -r", cwd=root_path)
|
|
160
244
|
print("Running pnpm audit fix...")
|
|
161
245
|
run_cmd("pnpm audit fix", cwd=root_path, check=False)
|
|
@@ -183,9 +267,28 @@ async def deps_upgrade_command(
|
|
|
183
267
|
print(f"No changes found after updating {package or 'all'}. Skipping MR.")
|
|
184
268
|
return
|
|
185
269
|
|
|
270
|
+
# Generate commit message and discover affected projects
|
|
271
|
+
if package == "all":
|
|
272
|
+
mr_title = f"fix({manager}): update dependencies"
|
|
273
|
+
body = f"Automated upgrade of all {manager} dependencies."
|
|
274
|
+
else:
|
|
275
|
+
mr_title = f"fix({manager}): update {package}"
|
|
276
|
+
body = f"Automated upgrade of {package}."
|
|
277
|
+
|
|
278
|
+
# Discovery
|
|
279
|
+
updated_pkgs = [package] if package != "all" else [pkg["name"] for pkg in outdated]
|
|
280
|
+
projects = _get_workspace_projects(root_path, manager, dirs, updated_pkgs)
|
|
281
|
+
if projects:
|
|
282
|
+
releases = ", ".join(projects)
|
|
283
|
+
body += f"\n\nReleases: {releases}"
|
|
284
|
+
|
|
186
285
|
if dry_run or skip_branch:
|
|
187
286
|
if dry_run:
|
|
188
|
-
print(
|
|
287
|
+
print("\n[DRY RUN] Would create MR:")
|
|
288
|
+
print(f"Title: {mr_title}")
|
|
289
|
+
print(f"Body:\n{body}\n")
|
|
290
|
+
else:
|
|
291
|
+
print("Changes applied to lockfiles. skipping branch/commit as requested.")
|
|
189
292
|
return
|
|
190
293
|
|
|
191
294
|
# Create and switch to new branch
|
|
@@ -204,9 +307,7 @@ async def deps_upgrade_command(
|
|
|
204
307
|
|
|
205
308
|
run_cmd("git add .", cwd=root_path)
|
|
206
309
|
|
|
207
|
-
|
|
208
|
-
commit_msg = f"{mr_title}\n\nAutomated upgrade of {package}."
|
|
209
|
-
run_cmd(f'git commit -m "{commit_msg}"', cwd=root_path)
|
|
310
|
+
run_cmd(["git", "commit", "-m", mr_title, "-m", body], cwd=root_path)
|
|
210
311
|
|
|
211
312
|
if final_token:
|
|
212
313
|
_push_branch(branch_name, final_token)
|
|
@@ -215,7 +316,7 @@ async def deps_upgrade_command(
|
|
|
215
316
|
client = GitLabProvider(token=final_token, project_id=final_project_id)
|
|
216
317
|
await client.create_mr(
|
|
217
318
|
title=mr_title,
|
|
218
|
-
description=
|
|
319
|
+
description=body,
|
|
219
320
|
source_branch=branch_name,
|
|
220
321
|
target_branch="main",
|
|
221
322
|
)
|
|
@@ -11,7 +11,6 @@ import shutil
|
|
|
11
11
|
import subprocess
|
|
12
12
|
import sys
|
|
13
13
|
from importlib.metadata import version as get_version
|
|
14
|
-
from importlib.resources import files
|
|
15
14
|
from pathlib import Path
|
|
16
15
|
from typing import Annotated
|
|
17
16
|
|
|
@@ -24,116 +23,36 @@ new_app = cyclopts.App(
|
|
|
24
23
|
)
|
|
25
24
|
|
|
26
25
|
# =============================================================================
|
|
27
|
-
# Template
|
|
26
|
+
# Template Utilities
|
|
28
27
|
# =============================================================================
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
"""{{ class_name }} DocType.
|
|
29
|
+
TEMPLATES_DIR = Path(__file__).parent.parent / "templates"
|
|
32
30
|
|
|
33
|
-
Auto-generated by `m new:doctype {{ name }}`.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
from __future__ import annotations
|
|
37
|
-
|
|
38
|
-
from typing import ClassVar
|
|
39
|
-
|
|
40
|
-
from framework_m import DocType, Field
|
|
41
31
|
|
|
32
|
+
def _get_template_path(category: str, name: str) -> Path:
|
|
33
|
+
"""Get the path to a template file.
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
Args:
|
|
36
|
+
category: Template category (e.g., "plugin", "app", "doctype")
|
|
37
|
+
name: Template filename (e.g., "package.json.template")
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
Returns:
|
|
40
|
+
Path to the template file
|
|
48
41
|
"""
|
|
42
|
+
return TEMPLATES_DIR / category / name
|
|
49
43
|
|
|
50
|
-
__doctype_name__: ClassVar[str] = "{{ class_name }}"
|
|
51
|
-
|
|
52
|
-
name: str = Field(description="Unique identifier")
|
|
53
|
-
|
|
54
|
-
class Meta:
|
|
55
|
-
"""DocType metadata."""
|
|
56
|
-
|
|
57
|
-
requires_auth: ClassVar[bool] = False # Allow access without login (dev)
|
|
58
|
-
apply_rls: ClassVar[bool] = False # All users can access all records (dev)
|
|
59
|
-
naming_rule: ClassVar[str] = "autoincrement"
|
|
60
|
-
is_submittable: ClassVar[bool] = False
|
|
61
|
-
api_resource: ClassVar[bool] = True # Expose via REST API
|
|
62
|
-
show_in_desk: ClassVar[bool] = True # Show in Desk UI
|
|
63
|
-
permissions: ClassVar[dict[str, list[str]]] = {
|
|
64
|
-
"create": ["All"],
|
|
65
|
-
"read": ["All"],
|
|
66
|
-
"write": ["All"],
|
|
67
|
-
"delete": ["All"],
|
|
68
|
-
}
|
|
69
|
-
'''
|
|
70
44
|
|
|
71
|
-
|
|
72
|
-
"""
|
|
45
|
+
def _load_template(category: str, name: str) -> str:
|
|
46
|
+
"""Load a template file's content.
|
|
73
47
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
from __future__ import annotations
|
|
78
|
-
|
|
79
|
-
from framework_m import Controller
|
|
80
|
-
from .doctype import {{ class_name }}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class {{ class_name }}Controller(Controller[{{ class_name }}]):
|
|
84
|
-
"""Controller for {{ class_name }} DocType.
|
|
48
|
+
Args:
|
|
49
|
+
category: Template category
|
|
50
|
+
name: Template filename
|
|
85
51
|
|
|
86
|
-
|
|
52
|
+
Returns:
|
|
53
|
+
Template content
|
|
87
54
|
"""
|
|
88
|
-
|
|
89
|
-
doctype = {{ class_name }}
|
|
90
|
-
|
|
91
|
-
async def before_save(self, doc: {{ class_name }}) -> None:
|
|
92
|
-
"""Called before saving a document."""
|
|
93
|
-
pass
|
|
94
|
-
|
|
95
|
-
async def after_save(self, doc: {{ class_name }}) -> None:
|
|
96
|
-
"""Called after saving a document."""
|
|
97
|
-
pass
|
|
98
|
-
'''
|
|
99
|
-
|
|
100
|
-
TEST_TEMPLATE = '''\
|
|
101
|
-
"""Tests for {{ class_name }} DocType.
|
|
102
|
-
|
|
103
|
-
Auto-generated by `m new:doctype {{ name }}`.
|
|
104
|
-
"""
|
|
105
|
-
|
|
106
|
-
from __future__ import annotations
|
|
107
|
-
|
|
108
|
-
import pytest
|
|
109
|
-
|
|
110
|
-
from .doctype import {{ class_name }}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class Test{{ class_name }}:
|
|
114
|
-
"""Tests for {{ class_name }}."""
|
|
115
|
-
|
|
116
|
-
def test_create_{{ snake_name }}(self) -> None:
|
|
117
|
-
"""{{ class_name }} should be creatable."""
|
|
118
|
-
doc = {{ class_name }}(name="test-001")
|
|
119
|
-
assert doc.name == "test-001"
|
|
120
|
-
|
|
121
|
-
def test_{{ snake_name }}_doctype_name(self) -> None:
|
|
122
|
-
"""{{ class_name }} should have correct doctype name."""
|
|
123
|
-
assert {{ class_name }}.__doctype_name__ == "{{ class_name }}"
|
|
124
|
-
'''
|
|
125
|
-
|
|
126
|
-
INIT_TEMPLATE = '''\
|
|
127
|
-
"""{{ class_name }} DocType package.
|
|
128
|
-
|
|
129
|
-
Auto-generated by `m new:doctype {{ name }}`.
|
|
130
|
-
"""
|
|
131
|
-
|
|
132
|
-
from .controller import {{ class_name }}Controller
|
|
133
|
-
from .doctype import {{ class_name }}
|
|
134
|
-
|
|
135
|
-
__all__ = ["{{ class_name }}", "{{ class_name }}Controller"]
|
|
136
|
-
'''
|
|
55
|
+
return _get_template_path(category, name).read_text()
|
|
137
56
|
|
|
138
57
|
|
|
139
58
|
# =============================================================================
|
|
@@ -428,14 +347,15 @@ def scaffold_doctype(
|
|
|
428
347
|
|
|
429
348
|
# Create doctype files (go in src/)
|
|
430
349
|
doctype_files = [
|
|
431
|
-
("__init__.py",
|
|
432
|
-
("doctype.py",
|
|
433
|
-
("controller.py",
|
|
350
|
+
("__init__.py", "doctype", "__init__.py.template"),
|
|
351
|
+
("doctype.py", "doctype", "doctype.py.template"),
|
|
352
|
+
("controller.py", "doctype", "controller.py.template"),
|
|
434
353
|
]
|
|
435
354
|
|
|
436
|
-
for filename,
|
|
355
|
+
for filename, category, template_name in doctype_files:
|
|
437
356
|
filepath = output_dir / filename
|
|
438
|
-
|
|
357
|
+
template_content = _load_template(category, template_name)
|
|
358
|
+
content = render_template(template_content, context)
|
|
439
359
|
filepath.write_text(content)
|
|
440
360
|
created_files[filename] = filepath
|
|
441
361
|
|
|
@@ -444,7 +364,8 @@ def scaffold_doctype(
|
|
|
444
364
|
test_dir.mkdir(parents=True, exist_ok=True)
|
|
445
365
|
test_filename = f"test_{snake_name}.py"
|
|
446
366
|
test_filepath = test_dir / test_filename
|
|
447
|
-
|
|
367
|
+
template_content = _load_template("doctype", "test.py.template")
|
|
368
|
+
test_content = render_template(template_content, context)
|
|
448
369
|
test_filepath.write_text(test_content)
|
|
449
370
|
created_files[test_filename] = test_filepath
|
|
450
371
|
|
|
@@ -556,81 +477,11 @@ def new_doctype_command(
|
|
|
556
477
|
# New App Command
|
|
557
478
|
# =============================================================================
|
|
558
479
|
|
|
559
|
-
# App template files (embedded for simplicity)
|
|
560
|
-
APP_PYPROJECT_TEMPLATE = """\
|
|
561
|
-
[project]
|
|
562
|
-
name = "{{ app_name }}"
|
|
563
|
-
version = "0.1.0"
|
|
564
|
-
description = "A Framework M application"
|
|
565
|
-
readme = "README.md"
|
|
566
|
-
requires-python = ">=3.12"
|
|
567
|
-
dependencies = [
|
|
568
|
-
"framework-m>={{ framework_version }}",
|
|
569
|
-
]
|
|
570
|
-
|
|
571
|
-
[dependency-groups]
|
|
572
|
-
dev = [
|
|
573
|
-
"framework-m-studio>={{ studio_version }}",
|
|
574
|
-
]
|
|
575
|
-
|
|
576
|
-
[project.entry-points."framework_m.apps"]
|
|
577
|
-
{{ app_name }} = "{{ app_name }}:app"
|
|
578
|
-
|
|
579
|
-
[build-system]
|
|
580
|
-
requires = ["hatchling"]
|
|
581
|
-
build-backend = "hatchling.build"
|
|
582
|
-
|
|
583
|
-
[tool.hatch.build.targets.wheel]
|
|
584
|
-
packages = ["src/{{ app_name }}"]
|
|
585
|
-
"""
|
|
586
|
-
|
|
587
|
-
APP_README_TEMPLATE = """\
|
|
588
|
-
# {{ class_name }}
|
|
589
|
-
|
|
590
|
-
A Framework M application.
|
|
591
|
-
|
|
592
|
-
## Getting Started
|
|
593
|
-
|
|
594
|
-
```bash
|
|
595
|
-
cd {{ app_name }}
|
|
596
|
-
uv sync
|
|
597
|
-
m dev
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
## Structure
|
|
601
|
-
|
|
602
|
-
```
|
|
603
|
-
{{ app_name }}/
|
|
604
|
-
├── src/
|
|
605
|
-
│ └── {{ app_name }}/ # App namespace
|
|
606
|
-
│ ├── __init__.py # App config
|
|
607
|
-
│ ├── doctypes/ # Your DocTypes go here
|
|
608
|
-
│ ├── services/ # Business logic (optional)
|
|
609
|
-
│ └── utils/ # Utilities (optional)
|
|
610
|
-
├── tests/ # Test files
|
|
611
|
-
├── pyproject.toml
|
|
612
|
-
└── README.md
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
## Adding DocTypes
|
|
616
|
-
|
|
617
|
-
```bash
|
|
618
|
-
m new:doctype Invoice
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
This creates:
|
|
622
|
-
- `src/{{ app_name }}/doctypes/invoice/` - DocType files
|
|
623
|
-
- `tests/doctypes/invoice/` - Test files
|
|
624
|
-
"""
|
|
625
|
-
|
|
626
480
|
|
|
627
481
|
# =============================================================================
|
|
628
482
|
# Frontend Plugin Templates (loaded from template files)
|
|
629
483
|
# =============================================================================
|
|
630
484
|
|
|
631
|
-
# Directory containing plugin template files
|
|
632
|
-
PLUGIN_TEMPLATES_DIR = Path(__file__).parent.parent / "templates" / "plugin"
|
|
633
|
-
|
|
634
485
|
|
|
635
486
|
def _load_plugin_template(name: str) -> str:
|
|
636
487
|
"""Load a plugin template file.
|
|
@@ -641,8 +492,7 @@ def _load_plugin_template(name: str) -> str:
|
|
|
641
492
|
Returns:
|
|
642
493
|
Template file contents
|
|
643
494
|
"""
|
|
644
|
-
|
|
645
|
-
return template_path.read_text()
|
|
495
|
+
return _load_template("plugin", name)
|
|
646
496
|
|
|
647
497
|
|
|
648
498
|
def scaffold_frontend_plugin(
|
|
@@ -677,9 +527,9 @@ def scaffold_frontend_plugin(
|
|
|
677
527
|
src_dir = frontend_dir / "src"
|
|
678
528
|
src_dir.mkdir(parents=True, exist_ok=True)
|
|
679
529
|
|
|
680
|
-
#
|
|
681
|
-
for
|
|
682
|
-
(src_dir /
|
|
530
|
+
# Ensure required subdirectories exist (ADR-0008)
|
|
531
|
+
for sub in ["pages", "components", "services"]:
|
|
532
|
+
(src_dir / sub).mkdir(parents=True, exist_ok=True)
|
|
683
533
|
|
|
684
534
|
created_files: dict[str, Path] = {}
|
|
685
535
|
|
|
@@ -687,20 +537,35 @@ def scaffold_frontend_plugin(
|
|
|
687
537
|
template_map = {
|
|
688
538
|
"package.json.template": frontend_dir / "package.json",
|
|
689
539
|
"plugin.config.ts.template": src_dir / "plugin.config.ts",
|
|
540
|
+
"index.tsx.template": src_dir / "index.tsx",
|
|
541
|
+
"index.html.template": frontend_dir / "index.html",
|
|
542
|
+
"theme.css.template": src_dir / "theme.css",
|
|
543
|
+
"vite.config.ts.template": frontend_dir / "vite.config.ts",
|
|
690
544
|
"vite.config.mfe.ts.template": frontend_dir / "vite.config.mfe.ts",
|
|
691
545
|
"tsconfig.json.template": frontend_dir / "tsconfig.json",
|
|
692
546
|
"README.md.template": frontend_dir / "README.md",
|
|
693
547
|
"Dashboard.tsx.template": src_dir / "pages" / "Dashboard.tsx",
|
|
548
|
+
".gitignore.template": frontend_dir / ".gitignore",
|
|
694
549
|
}
|
|
695
550
|
|
|
696
551
|
for template_name, output_path in template_map.items():
|
|
697
552
|
template_content = _load_plugin_template(template_name)
|
|
698
553
|
rendered = render_template(template_content, context)
|
|
554
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
699
555
|
output_path.write_text(rendered)
|
|
556
|
+
created_files[str(output_path.relative_to(app_dir))] = output_path
|
|
700
557
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
558
|
+
# Static files (copied as-is)
|
|
559
|
+
static_files = {
|
|
560
|
+
"favicon.png": frontend_dir / "public" / "favicon.png",
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
for static_name, output_path in static_files.items():
|
|
564
|
+
source_path = _get_template_path("plugin", static_name)
|
|
565
|
+
if source_path.exists():
|
|
566
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
567
|
+
shutil.copy2(source_path, output_path)
|
|
568
|
+
created_files[str(output_path.relative_to(app_dir))] = output_path
|
|
704
569
|
|
|
705
570
|
return created_files
|
|
706
571
|
|
|
@@ -758,27 +623,17 @@ def scaffold_app(
|
|
|
758
623
|
created_files: dict[str, Path] = {}
|
|
759
624
|
|
|
760
625
|
# Create <app_name>/__init__.py with app configuration
|
|
761
|
-
app_init_content =
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
"""
|
|
765
|
-
|
|
766
|
-
# App configuration - discovered via entry points
|
|
767
|
-
app = {{
|
|
768
|
-
"name": "{snake_name}",
|
|
769
|
-
"title": "{class_name}",
|
|
770
|
-
"description": "A Framework M application",
|
|
771
|
-
}}
|
|
772
|
-
'''
|
|
626
|
+
app_init_content = render_template(
|
|
627
|
+
_load_template("app", "__init__.py.template"), context
|
|
628
|
+
)
|
|
773
629
|
app_init_path = namespace_dir / "__init__.py"
|
|
774
630
|
app_init_path.write_text(app_init_content)
|
|
775
631
|
created_files[f"src/{snake_name}/__init__.py"] = app_init_path
|
|
776
632
|
|
|
777
633
|
# Create <app_name>/doctypes/__init__.py
|
|
778
|
-
doctypes_init_content =
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
'''
|
|
634
|
+
doctypes_init_content = render_template(
|
|
635
|
+
_load_template("app", "doctypes_init.py.template"), context
|
|
636
|
+
)
|
|
782
637
|
doctypes_init_path = doctypes_dir / "__init__.py"
|
|
783
638
|
doctypes_init_path.write_text(doctypes_init_content)
|
|
784
639
|
created_files[f"src/{snake_name}/doctypes/__init__.py"] = doctypes_init_path
|
|
@@ -789,13 +644,17 @@ app = {{
|
|
|
789
644
|
created_files["tests/__init__.py"] = tests_init_path
|
|
790
645
|
|
|
791
646
|
# Create pyproject.toml
|
|
792
|
-
pyproject_content = render_template(
|
|
647
|
+
pyproject_content = render_template(
|
|
648
|
+
_load_template("app", "pyproject.toml.template"), context
|
|
649
|
+
)
|
|
793
650
|
pyproject_path = app_dir / "pyproject.toml"
|
|
794
651
|
pyproject_path.write_text(pyproject_content)
|
|
795
652
|
created_files["pyproject.toml"] = pyproject_path
|
|
796
653
|
|
|
797
654
|
# Create README.md
|
|
798
|
-
readme_content = render_template(
|
|
655
|
+
readme_content = render_template(
|
|
656
|
+
_load_template("app", "README.md.template"), context
|
|
657
|
+
)
|
|
799
658
|
readme_path = app_dir / "README.md"
|
|
800
659
|
readme_path.write_text(readme_content)
|
|
801
660
|
created_files["README.md"] = readme_path
|
|
@@ -944,38 +803,21 @@ def new_frontend_command(
|
|
|
944
803
|
and installs dependencies. The template includes:
|
|
945
804
|
- React + TypeScript + Vite
|
|
946
805
|
- @framework-m/desk npm package integration
|
|
947
|
-
-
|
|
948
|
-
-
|
|
806
|
+
- Unified Sandbox Architecture (Shell + Plugin mode)
|
|
807
|
+
- Standardized library-driven tokens (@framework-m/ui)
|
|
949
808
|
|
|
950
809
|
Examples:
|
|
951
810
|
m new:frontend # Initialize in ./frontend
|
|
952
811
|
m new:frontend ../my-frontend # Custom location
|
|
953
812
|
"""
|
|
954
|
-
#
|
|
955
|
-
|
|
956
|
-
target = Path("frontend")
|
|
957
|
-
|
|
958
|
-
# Resolve to absolute path
|
|
959
|
-
target = target.resolve()
|
|
960
|
-
|
|
961
|
-
# Find template source from framework_m package
|
|
962
|
-
try:
|
|
963
|
-
template_resource = files("framework_m_studio") / "templates" / "frontend"
|
|
964
|
-
if not template_resource.is_dir():
|
|
965
|
-
msg = "Frontend template not found in framework_m package"
|
|
966
|
-
raise RuntimeError(msg)
|
|
967
|
-
|
|
968
|
-
# Convert to Path for file operations
|
|
969
|
-
template_source = Path(str(template_resource))
|
|
970
|
-
except Exception as e:
|
|
971
|
-
msg = f"Failed to locate template: {e}"
|
|
972
|
-
raise RuntimeError(msg) from e
|
|
813
|
+
# Detect app name for context
|
|
814
|
+
app_name = detect_app() or "frontend_app"
|
|
973
815
|
|
|
974
|
-
|
|
975
|
-
|
|
816
|
+
# Default to ./frontend if target is not provided
|
|
817
|
+
target = target or Path("frontend")
|
|
976
818
|
|
|
977
|
-
#
|
|
978
|
-
|
|
819
|
+
# Use unified template-rendering scaffolding
|
|
820
|
+
scaffold_frontend_plugin(app_name, target.parent, target.name)
|
|
979
821
|
|
|
980
822
|
# Install dependencies
|
|
981
823
|
_install_dependencies(target)
|