ntc-dev-kit 1.1.0__tar.gz → 1.2.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.
- {ntc_dev_kit-1.1.0/ntc_dev_kit.egg-info → ntc_dev_kit-1.2.0}/PKG-INFO +26 -2
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/README.md +25 -1
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/__init__.py +1 -1
- ntc_dev_kit-1.2.0/ntc/cli_enhanced.py +421 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/main.py +2 -2
- ntc_dev_kit-1.2.0/ntc/templates/auth_app/migrations/0001_initial.py +50 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/main.py +19 -19
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/utils/output.py +10 -0
- ntc_dev_kit-1.2.0/ntc/utils/prompts.py +271 -0
- ntc_dev_kit-1.2.0/ntc/wizard.py +294 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0/ntc_dev_kit.egg-info}/PKG-INFO +26 -2
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc_dev_kit.egg-info/SOURCES.txt +3 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/pyproject.toml +1 -1
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/setup.py +1 -1
- ntc_dev_kit-1.1.0/ntc/cli_enhanced.py +0 -934
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/LICENSE +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/MANIFEST.in +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/app_creator.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/cli.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/composer/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/composer/main.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/deployment/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/admin.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/apps.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/models.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/serializers.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/tests.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/urls.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/auth_app/views.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/drf_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/structure.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/.entry/start_core_backend.sh +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/.entry/start_tasks_backend.sh +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/CLAUDE.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/README.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/app_admin.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/app_apps.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/app_models.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/app_urls.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/app_views.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/common_apps.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/apps/common_models.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/config/gunicorn_config.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/config/http.conf +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/exceptions/handler.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/formatter.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/logger.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/pagination.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/response_wrapper.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/services/azure/email/backend.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/services/azure/email/client.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/services/azure/email/notifier.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/services/object_storage.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/core/utils/request.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/asgi.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/celery.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/dev_settings.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/django_settings.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/prod_settings.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/project_init.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/schema.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/test_settings.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/urls.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/django_project/wsgi.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/docker/Dockerfile +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/docker/captain-definition +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/docker/docker-compose.yml +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/knowledge/knowledge_description.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/knowledge/knowledge_design_pattern.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/knowledge/knowledge_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/README.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/django_env.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/django_requirements.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/django_requirements_dev.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/dockerignore.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/gitattributes.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/gitignore.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/manage.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/pytest_ini.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/drf_structure/templates/root/ruff_toml.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/.gitignore +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/.knowledge/knowledge_description.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/.knowledge/knowledge_design_pattern.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/.knowledge/knowledge_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/CLAUDE.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/analysis_options.yaml +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/core/config/app_config.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/core/config/environment.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/core/constants/app_constants.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/core/network/dio_client.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/features/home/presentation/home_screen.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/l10n/app_localizations.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/main.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/services/api_service.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/shared/localization/locale_provider.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/shared/theme/app_theme.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/lib/shared/theme/theme_provider.dart +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/main.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/pubspec.yaml +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/flutter/structure.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/.env.example +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/.gitignore +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/CLAUDE.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/README.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/eslint.config.mjs +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/knowledge/knowledge_description.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/knowledge/knowledge_design_pattern.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/knowledge/knowledge_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/main.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/next.config.js +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/package.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/app/globals.css +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/app/layout.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/app/page.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/components/Header.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/services/api.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/services/server.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/src/utils/constants.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/structure.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/nextjs/tsconfig.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/.env.example +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/.gitignore +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/CLAUDE.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/README.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/eslint.config.js +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/index.html +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/knowledge/knowledge_description.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/knowledge/knowledge_design_pattern.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/knowledge/knowledge_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/main.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/package.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/App.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/components/ProtectedRoute.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/components/Sidebar.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/components/TopNav.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/context/AuthContext.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/context/ThemeContext.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/context/WorkspaceContext.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/hooks/useApi.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/index.css +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/layouts/AuthLayout.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/layouts/DashboardLayout.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/main.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/pages/DashboardPage.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/pages/auth/LoginPage.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/services/api.service.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/services/base.service.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/services/token.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/src/vite-env.d.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/structure.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/tsconfig.app.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/tsconfig.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/tsconfig.node.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_admin/vite.config.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/App.css +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/CLAUDE.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/index.css +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/index.html +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/knowledge/knowledge_description.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/knowledge/knowledge_design_pattern.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/knowledge/knowledge_structure.md +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/main.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/package.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/App.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/components/Header.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/main.tsx +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/services/api.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/utils/constants.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/src/vite-env.d.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/structure.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/tsconfig.app.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/tsconfig.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/tsconfig.node.json +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/templates/react_structure/vite.config.ts +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/ui/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/ui/app.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/utils/__init__.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/utils/environment.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/utils/shell.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc/utils/validation.py +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc_dev_kit.egg-info/dependency_links.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc_dev_kit.egg-info/entry_points.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc_dev_kit.egg-info/requires.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/ntc_dev_kit.egg-info/top_level.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/requirements.txt +0 -0
- {ntc_dev_kit-1.1.0 → ntc_dev_kit-1.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ntc-dev-kit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Nexent Toolkit Console - A CLI tool for scaffolding Django REST Framework, React, Next.js, and Flutter projects
|
|
5
5
|
Home-page: https://github.com/nexent/ntc
|
|
6
6
|
Author: Nexent
|
|
@@ -97,7 +97,31 @@ ntc init --technology flutter
|
|
|
97
97
|
ntc init
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
A few questions, asked inline: project name, what you're building, where it goes, then the
|
|
101
|
+
options for that technology (sign-in and Python environment for Django; installing dependencies
|
|
102
|
+
for the others), a summary, and **Create?**. The defaults are already selected, so Enter takes
|
|
103
|
+
them; **↑/↓** move, a **number key** picks an option at once, **Esc** cancels without writing
|
|
104
|
+
anything. Each answer collapses to one line, and the only progress shown is for real work
|
|
105
|
+
(creating the environment, installing packages).
|
|
106
|
+
|
|
107
|
+
### Without questions
|
|
108
|
+
|
|
109
|
+
Every answer can be given as a flag; with `--yes` nothing is asked (scripts, CI, AI agents):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
ntc init -t django --name shop-api --with-auth --env venv --yes
|
|
113
|
+
ntc init -t nextjs --name site --install --yes
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Flag | Meaning |
|
|
117
|
+
|------|---------|
|
|
118
|
+
| `-t`, `--technology` | `django`, `nextjs`, `react-admin`, `react`, `flutter` |
|
|
119
|
+
| `--name` | Project name (`.` = the current folder) |
|
|
120
|
+
| `--path` | Folder to create the project in (default: current folder) |
|
|
121
|
+
| `--with-auth` / `--no-auth` | Django: include the sign-in app (custom User model, JWT, migration included) |
|
|
122
|
+
| `--env` | Django: `venv`, `conda`, `existing` (the active virtualenv) or `skip` |
|
|
123
|
+
| `--install` / `--no-install` | Others: run `npm install` / `flutter pub get` |
|
|
124
|
+
| `--yes`, `-y` | Ask nothing; needs `--name` and `--technology` |
|
|
101
125
|
|
|
102
126
|
### Technology Options
|
|
103
127
|
|
|
@@ -57,7 +57,31 @@ ntc init --technology flutter
|
|
|
57
57
|
ntc init
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
A few questions, asked inline: project name, what you're building, where it goes, then the
|
|
61
|
+
options for that technology (sign-in and Python environment for Django; installing dependencies
|
|
62
|
+
for the others), a summary, and **Create?**. The defaults are already selected, so Enter takes
|
|
63
|
+
them; **↑/↓** move, a **number key** picks an option at once, **Esc** cancels without writing
|
|
64
|
+
anything. Each answer collapses to one line, and the only progress shown is for real work
|
|
65
|
+
(creating the environment, installing packages).
|
|
66
|
+
|
|
67
|
+
### Without questions
|
|
68
|
+
|
|
69
|
+
Every answer can be given as a flag; with `--yes` nothing is asked (scripts, CI, AI agents):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
ntc init -t django --name shop-api --with-auth --env venv --yes
|
|
73
|
+
ntc init -t nextjs --name site --install --yes
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
| Flag | Meaning |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| `-t`, `--technology` | `django`, `nextjs`, `react-admin`, `react`, `flutter` |
|
|
79
|
+
| `--name` | Project name (`.` = the current folder) |
|
|
80
|
+
| `--path` | Folder to create the project in (default: current folder) |
|
|
81
|
+
| `--with-auth` / `--no-auth` | Django: include the sign-in app (custom User model, JWT, migration included) |
|
|
82
|
+
| `--env` | Django: `venv`, `conda`, `existing` (the active virtualenv) or `skip` |
|
|
83
|
+
| `--install` / `--no-install` | Others: run `npm install` / `flutter pub get` |
|
|
84
|
+
| `--yes`, `-y` | Ask nothing; needs `--name` and `--technology` |
|
|
61
85
|
|
|
62
86
|
### Technology Options
|
|
63
87
|
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
from colorama import Fore, Style, init
|
|
6
|
+
from ntc.utils.validation import is_valid_project_name
|
|
7
|
+
|
|
8
|
+
# Commands import their generators when they run, so `ntc --help` and the first question of
|
|
9
|
+
# `ntc init` appear without loading every template module first.
|
|
10
|
+
|
|
11
|
+
# Initialize colorama for cross-platform colored output
|
|
12
|
+
init(autoreset=True)
|
|
13
|
+
|
|
14
|
+
def print_banner():
|
|
15
|
+
"""Display minimal welcome banner."""
|
|
16
|
+
print(f"\n{Fore.WHITE}{Style.BRIGHT} ntc{Style.RESET_ALL} {Fore.LIGHTBLACK_EX}— project scaffolding tool{Style.RESET_ALL}")
|
|
17
|
+
print()
|
|
18
|
+
|
|
19
|
+
def print_success(message):
|
|
20
|
+
"""Print success message with green color and checkmark."""
|
|
21
|
+
print(f"{Fore.GREEN}✅ {message}{Style.RESET_ALL}")
|
|
22
|
+
|
|
23
|
+
def print_error(message):
|
|
24
|
+
"""Print error message with red color and X mark."""
|
|
25
|
+
print(f"{Fore.RED}❌ {message}{Style.RESET_ALL}")
|
|
26
|
+
|
|
27
|
+
def print_warning(message):
|
|
28
|
+
"""Print warning message with yellow color and warning sign."""
|
|
29
|
+
print(f"{Fore.YELLOW}⚠️ {message}{Style.RESET_ALL}")
|
|
30
|
+
|
|
31
|
+
def print_info(message):
|
|
32
|
+
"""Print info message with blue color and info icon."""
|
|
33
|
+
print(f"{Fore.CYAN}ℹ️ {message}{Style.RESET_ALL}")
|
|
34
|
+
|
|
35
|
+
def animate_dependency_install(requirements_path=None, pip_command=None, env_type="system"):
|
|
36
|
+
"""Show real dependency installation with progress animation."""
|
|
37
|
+
import subprocess
|
|
38
|
+
import threading
|
|
39
|
+
|
|
40
|
+
if not requirements_path or not os.path.exists(requirements_path):
|
|
41
|
+
# Fallback to simulation if no requirements file
|
|
42
|
+
dependencies = [
|
|
43
|
+
"Resolving dependencies",
|
|
44
|
+
"Downloading packages",
|
|
45
|
+
"Installing Django",
|
|
46
|
+
"Installing DRF",
|
|
47
|
+
"Installing Celery",
|
|
48
|
+
"Installing CORS headers",
|
|
49
|
+
"Configuring environment",
|
|
50
|
+
"Setting up database",
|
|
51
|
+
"Creating migrations",
|
|
52
|
+
"Finalizing setup"
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
print(f"\n{Fore.MAGENTA}📦 Installing Dependencies{Style.RESET_ALL}")
|
|
56
|
+
|
|
57
|
+
for i, dep in enumerate(dependencies, 1):
|
|
58
|
+
progress = int((i / len(dependencies)) * 100)
|
|
59
|
+
|
|
60
|
+
# Show animation for each dependency
|
|
61
|
+
for j in range(5): # 5 animation cycles per dependency
|
|
62
|
+
frame = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"][j % 10]
|
|
63
|
+
# Clear line and print new content
|
|
64
|
+
print(f"\r{' ' * 80}\r{Fore.CYAN}{frame} {dep}... {Fore.YELLOW}[{progress}%]{Style.RESET_ALL}", end="", flush=True)
|
|
65
|
+
time.sleep(0.2)
|
|
66
|
+
|
|
67
|
+
print(f"\r{' ' * 80}\r{Fore.GREEN}✅ All dependencies installed successfully! {Fore.YELLOW}[100%]{Style.RESET_ALL}")
|
|
68
|
+
print()
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
# Real dependency installation with animation
|
|
72
|
+
print(f"\n{Fore.MAGENTA}📦 Installing Dependencies{Style.RESET_ALL}")
|
|
73
|
+
|
|
74
|
+
# Determine the pip command to use
|
|
75
|
+
if pip_command is None:
|
|
76
|
+
# Default to system pip
|
|
77
|
+
pip_command = [sys.executable, "-m", "pip", "install", "-r", requirements_path]
|
|
78
|
+
|
|
79
|
+
# Animation state
|
|
80
|
+
animation_running = True
|
|
81
|
+
install_complete = False
|
|
82
|
+
install_success = False
|
|
83
|
+
error_message = ""
|
|
84
|
+
|
|
85
|
+
def run_pip_install():
|
|
86
|
+
nonlocal install_complete, install_success, error_message
|
|
87
|
+
try:
|
|
88
|
+
# Run pip install with suppressed output
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
pip_command,
|
|
91
|
+
capture_output=True,
|
|
92
|
+
text=True,
|
|
93
|
+
check=True
|
|
94
|
+
)
|
|
95
|
+
install_success = True
|
|
96
|
+
except subprocess.CalledProcessError as e:
|
|
97
|
+
install_success = False
|
|
98
|
+
error_message = str(e)
|
|
99
|
+
finally:
|
|
100
|
+
install_complete = True
|
|
101
|
+
|
|
102
|
+
# Start installation in background thread
|
|
103
|
+
install_thread = threading.Thread(target=run_pip_install)
|
|
104
|
+
install_thread.start()
|
|
105
|
+
|
|
106
|
+
# Show animation while installation runs
|
|
107
|
+
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
108
|
+
frame_index = 0
|
|
109
|
+
|
|
110
|
+
while not install_complete:
|
|
111
|
+
frame = frames[frame_index % len(frames)]
|
|
112
|
+
# Clear line completely before writing new content
|
|
113
|
+
env_msg = f" ({env_type} environment)" if env_type != "system" else ""
|
|
114
|
+
print(f"\r{' ' * 80}\r{Fore.CYAN}{frame} Installing packages{env_msg}...{Style.RESET_ALL}", end="", flush=True)
|
|
115
|
+
time.sleep(0.1)
|
|
116
|
+
frame_index += 1
|
|
117
|
+
|
|
118
|
+
# Wait for thread to complete
|
|
119
|
+
install_thread.join()
|
|
120
|
+
|
|
121
|
+
# Show final result
|
|
122
|
+
if install_success:
|
|
123
|
+
print(f"\r{' ' * 80}\r{Fore.GREEN}✅ All dependencies installed successfully!{Style.RESET_ALL}")
|
|
124
|
+
else:
|
|
125
|
+
print(f"\r{' ' * 80}\r{Fore.RED}❌ Failed to install dependencies: {error_message}{Style.RESET_ALL}")
|
|
126
|
+
print(f"{Fore.YELLOW}💡 You can manually install later with: pip install -r requirements.txt{Style.RESET_ALL}")
|
|
127
|
+
|
|
128
|
+
print()
|
|
129
|
+
|
|
130
|
+
def run_doctor():
|
|
131
|
+
"""Check setup and fix common issues like PATH configuration."""
|
|
132
|
+
import shutil
|
|
133
|
+
import site
|
|
134
|
+
|
|
135
|
+
# Nexent brand palette
|
|
136
|
+
DIM = Fore.LIGHTBLACK_EX
|
|
137
|
+
ACCENT = Fore.WHITE
|
|
138
|
+
OK = Fore.GREEN
|
|
139
|
+
WARN = Fore.YELLOW
|
|
140
|
+
ERR = Fore.RED
|
|
141
|
+
BOLD = Style.BRIGHT
|
|
142
|
+
RESET = Style.RESET_ALL
|
|
143
|
+
|
|
144
|
+
def _ok(text):
|
|
145
|
+
print(f" {OK} {text}{RESET}")
|
|
146
|
+
|
|
147
|
+
def _err(text):
|
|
148
|
+
print(f" {ERR} {text}{RESET}")
|
|
149
|
+
|
|
150
|
+
def _warn(text):
|
|
151
|
+
print(f" {WARN} {text}{RESET}")
|
|
152
|
+
|
|
153
|
+
def _dim(text):
|
|
154
|
+
print(f" {DIM}{text}{RESET}")
|
|
155
|
+
|
|
156
|
+
# Minimal Nexent header
|
|
157
|
+
print(f"\n{BOLD}{Fore.WHITE} NEXENT{RESET}")
|
|
158
|
+
print(f" {DIM}Future Awaits{RESET}")
|
|
159
|
+
print(f" {DIM}{'─' * 50}{RESET}")
|
|
160
|
+
print(f" {Fore.WHITE}SETUP DIAGNOSTICS{RESET}\n")
|
|
161
|
+
|
|
162
|
+
issues_found = 0
|
|
163
|
+
issues_fixed = 0
|
|
164
|
+
|
|
165
|
+
# 1. Python
|
|
166
|
+
print(f" {Fore.WHITE}Python{RESET}")
|
|
167
|
+
py_version = sys.version_info
|
|
168
|
+
if py_version >= (3, 10):
|
|
169
|
+
_ok(f"{py_version.major}.{py_version.minor}.{py_version.micro}")
|
|
170
|
+
else:
|
|
171
|
+
_err(f"{py_version.major}.{py_version.minor} — >= 3.10 required")
|
|
172
|
+
issues_found += 1
|
|
173
|
+
|
|
174
|
+
# 2. Dependencies
|
|
175
|
+
print(f"\n {Fore.WHITE}Dependencies{RESET}")
|
|
176
|
+
deps_ok = True
|
|
177
|
+
for mod, name in [("colorama", "colorama"), ("yaml", "pyyaml")]:
|
|
178
|
+
try:
|
|
179
|
+
__import__(mod)
|
|
180
|
+
_ok(name)
|
|
181
|
+
except ImportError:
|
|
182
|
+
_err(name)
|
|
183
|
+
deps_ok = False
|
|
184
|
+
if not deps_ok:
|
|
185
|
+
issues_found += 1
|
|
186
|
+
_dim(" Run: pip install colorama pyyaml")
|
|
187
|
+
|
|
188
|
+
# 3. Command accessibility
|
|
189
|
+
print(f"\n {Fore.WHITE}Command{RESET}")
|
|
190
|
+
ntc_path = shutil.which("ntc")
|
|
191
|
+
if ntc_path:
|
|
192
|
+
_ok("ntc found")
|
|
193
|
+
_dim(f" {ntc_path}")
|
|
194
|
+
else:
|
|
195
|
+
_err("ntc not in PATH")
|
|
196
|
+
issues_found += 1
|
|
197
|
+
|
|
198
|
+
# 4. Scripts directory
|
|
199
|
+
print(f"\n {Fore.WHITE}Scripts Directory{RESET}")
|
|
200
|
+
scripts_dir = os.path.join(site.USER_BASE, "Scripts")
|
|
201
|
+
if os.path.exists(scripts_dir):
|
|
202
|
+
_ok(scripts_dir)
|
|
203
|
+
else:
|
|
204
|
+
_warn("missing — creating...")
|
|
205
|
+
os.makedirs(scripts_dir, exist_ok=True)
|
|
206
|
+
_ok("created")
|
|
207
|
+
issues_fixed += 1
|
|
208
|
+
|
|
209
|
+
# 5. PATH
|
|
210
|
+
if os.name == "nt":
|
|
211
|
+
print(f"\n {Fore.WHITE}PATH{RESET}")
|
|
212
|
+
current_path = os.environ.get("PATH", "")
|
|
213
|
+
if scripts_dir.lower() in current_path.lower():
|
|
214
|
+
_ok("Scripts directory in PATH")
|
|
215
|
+
else:
|
|
216
|
+
_warn("Scripts directory not in PATH")
|
|
217
|
+
try:
|
|
218
|
+
import winreg
|
|
219
|
+
with winreg.OpenKey(
|
|
220
|
+
winreg.HKEY_CURRENT_USER, "Environment", 0,
|
|
221
|
+
winreg.KEY_READ | winreg.KEY_WRITE,
|
|
222
|
+
) as key:
|
|
223
|
+
existing, _ = winreg.QueryValueEx(key, "PATH")
|
|
224
|
+
if scripts_dir.lower() not in existing.lower():
|
|
225
|
+
new_path = f"{existing};{scripts_dir}"
|
|
226
|
+
winreg.SetValueEx(key, "PATH", 0, winreg.REG_EXPAND_SZ, new_path)
|
|
227
|
+
os.environ["PATH"] = new_path
|
|
228
|
+
_ok("added to registry")
|
|
229
|
+
issues_fixed += 1
|
|
230
|
+
else:
|
|
231
|
+
_ok("in registry (restart needed)")
|
|
232
|
+
except Exception as e:
|
|
233
|
+
_err(f"registry edit failed: {e}")
|
|
234
|
+
_dim(f" Add manually: {scripts_dir}")
|
|
235
|
+
issues_found += 1
|
|
236
|
+
|
|
237
|
+
# 6. Package version
|
|
238
|
+
print(f"\n {Fore.WHITE}Package{RESET}")
|
|
239
|
+
try:
|
|
240
|
+
import ntc
|
|
241
|
+
_ok(f"ntc-dev-kit {ntc.__version__}")
|
|
242
|
+
except (ImportError, AttributeError):
|
|
243
|
+
_err("ntc-dev-kit not installed")
|
|
244
|
+
issues_found += 1
|
|
245
|
+
|
|
246
|
+
# Summary
|
|
247
|
+
print(f"\n {DIM}{'─' * 50}{RESET}")
|
|
248
|
+
if issues_found == 0 and issues_fixed == 0:
|
|
249
|
+
print(f" {OK}Ready.{RESET}")
|
|
250
|
+
elif issues_fixed > 0:
|
|
251
|
+
print(f" {OK}Fixed {issues_fixed}.{RESET}")
|
|
252
|
+
if issues_found > 0:
|
|
253
|
+
print(f" {WARN}{issues_found} remaining.{RESET}")
|
|
254
|
+
else:
|
|
255
|
+
print(f" {DIM}Restart terminal for changes.{RESET}")
|
|
256
|
+
else:
|
|
257
|
+
print(f" {ERR}{issues_found} issue(s) found.{RESET}")
|
|
258
|
+
print(f" {DIM}Run 'ntc doctor' again after fixing.{RESET}")
|
|
259
|
+
print(f" {DIM}{'─' * 50}{RESET}\n")
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _use_utf8_console():
|
|
263
|
+
"""Print emoji and box-drawing characters on any console.
|
|
264
|
+
|
|
265
|
+
A Windows console on cp1252 (the default, and what scripts, CI and editor terminals get)
|
|
266
|
+
can't encode them: the very first print raised UnicodeEncodeError and ntc init crashed.
|
|
267
|
+
Characters the console truly can't show are replaced instead of raising."""
|
|
268
|
+
for stream in (sys.stdout, sys.stderr):
|
|
269
|
+
try:
|
|
270
|
+
stream.reconfigure(encoding='utf-8', errors='replace')
|
|
271
|
+
except (AttributeError, ValueError):
|
|
272
|
+
pass # not a reconfigurable text stream (redirected to an object, Python < 3.7)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def main():
|
|
276
|
+
_use_utf8_console()
|
|
277
|
+
parser = argparse.ArgumentParser(
|
|
278
|
+
description="ntc — project scaffolding tool",
|
|
279
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
280
|
+
epilog="""
|
|
281
|
+
Examples:
|
|
282
|
+
ntc init # New project: a few questions, defaults pre-selected
|
|
283
|
+
ntc init -t django # Skip the "what are you building" question
|
|
284
|
+
ntc init -t django --name shop-api --with-auth --env venv --yes
|
|
285
|
+
# No questions at all (scripts, CI, AI agents)
|
|
286
|
+
ntc init -t nextjs --name site --install --yes
|
|
287
|
+
ntc compose myproject # Compose full-stack project with multiple components
|
|
288
|
+
ntc start # Start all services from ntc.yml configuration
|
|
289
|
+
ntc create app myapp # Create new Django app
|
|
290
|
+
ntc drf init path name # Legacy Django REST Framework initialization
|
|
291
|
+
"""
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
295
|
+
|
|
296
|
+
# Enhanced init command
|
|
297
|
+
init_parser = subparsers.add_parser("init", help="Interactive project initialization")
|
|
298
|
+
init_parser.add_argument('--technology', '-t', type=str,
|
|
299
|
+
choices=['django', 'react', 'react-admin', 'nextjs', 'flutter'],
|
|
300
|
+
help='Technology to use (django, react, react-admin, nextjs, flutter)')
|
|
301
|
+
init_parser.add_argument("--backend",
|
|
302
|
+
choices=["django", "drf", "laravel"],
|
|
303
|
+
help="Backend technology")
|
|
304
|
+
init_parser.add_argument("--frontend",
|
|
305
|
+
choices=["react", "react-admin", "nextjs", "flutter"],
|
|
306
|
+
help="Frontend technology")
|
|
307
|
+
init_parser.add_argument("--name", help="Project name ('.' = the current directory's name)")
|
|
308
|
+
init_parser.add_argument("--path", help="Directory to create the project in (default: current directory)")
|
|
309
|
+
auth_group = init_parser.add_mutually_exclusive_group()
|
|
310
|
+
auth_group.add_argument("--with-auth", dest="with_auth", action="store_true", default=None,
|
|
311
|
+
help="Django: include the authentication app (custom User model, JWT endpoints)")
|
|
312
|
+
auth_group.add_argument("--no-auth", dest="with_auth", action="store_false",
|
|
313
|
+
help="Django: no authentication app")
|
|
314
|
+
init_parser.add_argument("--env", choices=["venv", "conda", "existing", "skip"],
|
|
315
|
+
help="Django: Python environment - create a venv/conda env, install into the "
|
|
316
|
+
"active one, or skip")
|
|
317
|
+
install_group = init_parser.add_mutually_exclusive_group()
|
|
318
|
+
install_group.add_argument("--install", dest="install", action="store_true", default=None,
|
|
319
|
+
help="Next.js/React/Flutter: install dependencies (npm install / flutter pub get)")
|
|
320
|
+
install_group.add_argument("--no-install", dest="install", action="store_false",
|
|
321
|
+
help="Next.js/React/Flutter: don't install dependencies")
|
|
322
|
+
init_parser.add_argument("--yes", "-y", action="store_true",
|
|
323
|
+
help="Don't ask: use the options given and defaults for the rest "
|
|
324
|
+
"(requires --name and --technology)")
|
|
325
|
+
|
|
326
|
+
# Create command for apps
|
|
327
|
+
create_parser = subparsers.add_parser("create", help="Create new components")
|
|
328
|
+
create_subparsers = create_parser.add_subparsers(dest="create_type", help="Type of component to create")
|
|
329
|
+
|
|
330
|
+
# Create app subcommand
|
|
331
|
+
app_parser = create_subparsers.add_parser("app", help="Create new Django app with NTC structure")
|
|
332
|
+
app_parser.add_argument("app_name", help="Name of the app to create")
|
|
333
|
+
url_group = app_parser.add_mutually_exclusive_group()
|
|
334
|
+
url_group.add_argument("--no-url", action="store_true",
|
|
335
|
+
help="Don't add the app's URLs anywhere; include them yourself")
|
|
336
|
+
url_group.add_argument("--url-prefix", default=None,
|
|
337
|
+
help="Add the app's URLs at the root urlpatterns under this prefix "
|
|
338
|
+
"(e.g. 'api/v2/'). Default: the project's api_v1 list (/api/v1/<app>/)")
|
|
339
|
+
|
|
340
|
+
# Legacy DRF command for backward compatibility
|
|
341
|
+
drf_parser = subparsers.add_parser("drf", help="Django REST Framework commands (legacy)")
|
|
342
|
+
drf_subparsers = drf_parser.add_subparsers(dest="drf_action")
|
|
343
|
+
drf_init_parser = drf_subparsers.add_parser("init", help="Initialize DRF project")
|
|
344
|
+
drf_init_parser.add_argument("path", help="Base path to create the project")
|
|
345
|
+
drf_init_parser.add_argument("name", help="Project name")
|
|
346
|
+
|
|
347
|
+
# Composer command for full-stack project composition
|
|
348
|
+
composer_parser = subparsers.add_parser("compose", help="Compose a full-stack project with multiple components")
|
|
349
|
+
composer_parser.add_argument("project_name", help="Name of the project")
|
|
350
|
+
composer_parser.add_argument("--path", help="Base path to create the project (default: current directory)")
|
|
351
|
+
|
|
352
|
+
# Start services command
|
|
353
|
+
start_parser = subparsers.add_parser("start", help="Start all services defined in ntc.yml")
|
|
354
|
+
start_parser.add_argument("--path", help="Path to project root directory (default: current directory)")
|
|
355
|
+
|
|
356
|
+
# Doctor command for setup diagnostics
|
|
357
|
+
doctor_parser = subparsers.add_parser("doctor", help="Check setup and fix common issues")
|
|
358
|
+
|
|
359
|
+
# TUI command for interactive terminal UI
|
|
360
|
+
tui_parser = subparsers.add_parser("tui", help="Launch interactive terminal UI")
|
|
361
|
+
|
|
362
|
+
args = parser.parse_args()
|
|
363
|
+
|
|
364
|
+
if args.command == "init":
|
|
365
|
+
technology = args.technology or args.frontend or args.backend
|
|
366
|
+
technology = {"drf": "django", "laravel": "django"}.get(technology, technology)
|
|
367
|
+
if args.yes and not (args.name and technology):
|
|
368
|
+
print_error("--yes needs --name and --technology, so there is nothing left to ask.")
|
|
369
|
+
sys.exit(2)
|
|
370
|
+
from ntc.wizard import run as run_wizard
|
|
371
|
+
created = run_wizard(technology=technology, name=args.name, path=args.path, with_auth=args.with_auth,
|
|
372
|
+
env_choice=args.env, install=args.install, assume_yes=args.yes)
|
|
373
|
+
sys.exit(0 if created else 1)
|
|
374
|
+
elif args.command == "create" and args.create_type == "app":
|
|
375
|
+
if not is_valid_project_name(args.app_name):
|
|
376
|
+
print_error("App name may only contain letters, numbers, underscores, and hyphens!")
|
|
377
|
+
sys.exit(1)
|
|
378
|
+
from ntc.app_creator import create_app_structure
|
|
379
|
+
create_app_structure(args.app_name, add_urls=not args.no_url, url_prefix=args.url_prefix)
|
|
380
|
+
elif args.command == "drf" and args.drf_action == "init":
|
|
381
|
+
# Legacy support
|
|
382
|
+
if not is_valid_project_name(args.name):
|
|
383
|
+
print_error("Project name may only contain letters, numbers, underscores, and hyphens!")
|
|
384
|
+
sys.exit(1)
|
|
385
|
+
from ntc.templates.drf_structure.main import init_drf_project
|
|
386
|
+
init_drf_project(args.path, args.name)
|
|
387
|
+
elif args.command == "compose":
|
|
388
|
+
# Composer for full-stack project composition
|
|
389
|
+
if not is_valid_project_name(args.project_name):
|
|
390
|
+
print_error("Project name may only contain letters, numbers, underscores, and hyphens!")
|
|
391
|
+
sys.exit(1)
|
|
392
|
+
from ntc.composer.main import compose_project
|
|
393
|
+
if args.path:
|
|
394
|
+
compose_project(args.project_name, args.path)
|
|
395
|
+
else:
|
|
396
|
+
compose_project(args.project_name)
|
|
397
|
+
elif args.command == "start":
|
|
398
|
+
# Start services from ntc.yml configuration
|
|
399
|
+
from ntc.composer.main import start_services
|
|
400
|
+
if args.path:
|
|
401
|
+
start_services(args.path)
|
|
402
|
+
else:
|
|
403
|
+
start_services()
|
|
404
|
+
elif args.command == "doctor":
|
|
405
|
+
run_doctor()
|
|
406
|
+
elif args.command == "tui":
|
|
407
|
+
from ntc.ui.app import run_tui
|
|
408
|
+
run_tui()
|
|
409
|
+
else:
|
|
410
|
+
# Show help if no command provided
|
|
411
|
+
print_banner()
|
|
412
|
+
print(f"\n {Fore.LIGHTBLACK_EX}Quick Start:{Style.RESET_ALL}")
|
|
413
|
+
print(f" {Fore.WHITE}ntc tui{Style.RESET_ALL} {Fore.LIGHTBLACK_EX}interactive terminal UI{Style.RESET_ALL}")
|
|
414
|
+
print(f" {Fore.WHITE}ntc init{Style.RESET_ALL} {Fore.LIGHTBLACK_EX}interactive setup{Style.RESET_ALL}")
|
|
415
|
+
print(f" {Fore.WHITE}ntc init -t django{Style.RESET_ALL} {Fore.LIGHTBLACK_EX}Django project{Style.RESET_ALL}")
|
|
416
|
+
print(f" {Fore.WHITE}ntc doctor{Style.RESET_ALL} {Fore.LIGHTBLACK_EX}check setup{Style.RESET_ALL}")
|
|
417
|
+
print()
|
|
418
|
+
parser.print_help()
|
|
419
|
+
|
|
420
|
+
if __name__ == "__main__":
|
|
421
|
+
main()
|
|
@@ -37,8 +37,8 @@ modules_to_register = [
|
|
|
37
37
|
("ntc.templates.flutter", os.path.join(this_dir, "templates", "flutter", "__init__.py")),
|
|
38
38
|
("ntc.templates.flutter.main", os.path.join(this_dir, "templates", "flutter", "main.py")),
|
|
39
39
|
("ntc.templates.auth_app", os.path.join(this_dir, "templates", "auth_app", "__init__.py")),
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
# Not ntc.ui / ntc.ui.app: they import textual (most of a second), and `ntc tui` imports
|
|
41
|
+
# them itself when it runs.
|
|
42
42
|
]
|
|
43
43
|
|
|
44
44
|
for modname, file_path in modules_to_register:
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Generated by Django 5.2.7 on 2026-10-20 14:53
|
|
2
|
+
|
|
3
|
+
import django.contrib.auth.models
|
|
4
|
+
import django.contrib.auth.validators
|
|
5
|
+
import django.utils.timezone
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
initial = True
|
|
12
|
+
|
|
13
|
+
dependencies = [
|
|
14
|
+
('auth', '0012_alter_user_first_name_max_length'),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
operations = [
|
|
18
|
+
migrations.CreateModel(
|
|
19
|
+
name='User',
|
|
20
|
+
fields=[
|
|
21
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
22
|
+
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
23
|
+
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
24
|
+
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
25
|
+
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
26
|
+
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
27
|
+
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
28
|
+
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
29
|
+
('email', models.EmailField(max_length=254, unique=True)),
|
|
30
|
+
('first_name', models.CharField(blank=True, max_length=30)),
|
|
31
|
+
('last_name', models.CharField(blank=True, max_length=30)),
|
|
32
|
+
('phone_number', models.CharField(blank=True, max_length=15)),
|
|
33
|
+
('date_of_birth', models.DateField(blank=True, null=True)),
|
|
34
|
+
('profile_picture', models.ImageField(blank=True, null=True, upload_to='profile_pics/')),
|
|
35
|
+
('is_verified', models.BooleanField(default=False)),
|
|
36
|
+
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
37
|
+
('updated_at', models.DateTimeField(auto_now=True)),
|
|
38
|
+
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
|
39
|
+
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
|
40
|
+
],
|
|
41
|
+
options={
|
|
42
|
+
'verbose_name': 'User',
|
|
43
|
+
'verbose_name_plural': 'Users',
|
|
44
|
+
'db_table': 'auth_user',
|
|
45
|
+
},
|
|
46
|
+
managers=[
|
|
47
|
+
('objects', django.contrib.auth.models.UserManager()),
|
|
48
|
+
],
|
|
49
|
+
),
|
|
50
|
+
]
|
|
@@ -8,8 +8,13 @@ import platform
|
|
|
8
8
|
from colorama import Fore, Style
|
|
9
9
|
from ntc.utils.output import print_success, print_error, print_warning, print_info, print_progress, print_package, print_download
|
|
10
10
|
|
|
11
|
-
def sanitize_project_name(name):
|
|
12
|
-
"""Sanitize project name by removing TLD and replacing dots with underscores.
|
|
11
|
+
def sanitize_project_name(name, quiet=False):
|
|
12
|
+
"""Sanitize project name by removing TLD and replacing dots with underscores.
|
|
13
|
+
quiet: don't print what changed (the setup wizard shows the resulting folder instead)."""
|
|
14
|
+
if quiet:
|
|
15
|
+
from ntc.utils import output
|
|
16
|
+
with output.silenced():
|
|
17
|
+
return sanitize_project_name(name)
|
|
13
18
|
# Common TLDs to remove
|
|
14
19
|
tlds = ['.com', '.org', '.net', '.io', '.co', '.app', '.dev', '.tech', '.ai', '.ly', '.me', '.tv', '.co.tz', '.tz', '.or.tz']
|
|
15
20
|
|
|
@@ -90,15 +95,6 @@ def activate_env(env_type, env_dir):
|
|
|
90
95
|
print_success("Virtual environment created and dependencies installed!")
|
|
91
96
|
print_info(f"To activate your environment, run: {activate_cmd}")
|
|
92
97
|
|
|
93
|
-
# Optionally open a new terminal (non-blocking) for user convenience
|
|
94
|
-
try:
|
|
95
|
-
if platform.system() == "Windows":
|
|
96
|
-
# No shell=True: passing args as a list lets Python quote each
|
|
97
|
-
# argument correctly instead of interpolating into a shell string.
|
|
98
|
-
subprocess.Popen(["cmd", "/c", "start", "cmd", "/k", activate_cmd])
|
|
99
|
-
print_info("A new terminal window has been opened with the environment activated.")
|
|
100
|
-
except Exception:
|
|
101
|
-
pass
|
|
102
98
|
|
|
103
99
|
def create_virtual_env(env_type, project_root):
|
|
104
100
|
"""
|
|
@@ -241,9 +237,10 @@ def install_requirements(env_type, env_dir, project_root):
|
|
|
241
237
|
print("❌ Python not found in PATH. Cannot create venv.")
|
|
242
238
|
sys.exit(1)
|
|
243
239
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
240
|
+
# create_virtual_env() has normally made it already; making it again cost a few seconds.
|
|
241
|
+
if not os.path.exists(env_dir):
|
|
242
|
+
subprocess.run([sys.executable, "-m", "venv", env_dir], check=True)
|
|
243
|
+
print(f"✅ Virtual environment created at: {env_dir}")
|
|
247
244
|
|
|
248
245
|
pip_path = os.path.join(env_dir, "Scripts" if os.name == "nt" else "bin", "pip")
|
|
249
246
|
|
|
@@ -251,8 +248,8 @@ def install_requirements(env_type, env_dir, project_root):
|
|
|
251
248
|
from ntc.cli_enhanced import animate_dependency_install
|
|
252
249
|
pip_command = [pip_path, "install", "-r", requirements_path]
|
|
253
250
|
animate_dependency_install(requirements_path, pip_command, "venv")
|
|
254
|
-
|
|
255
|
-
|
|
251
|
+
# requirements.txt is already pinned: a pip freeze here would replace it with every
|
|
252
|
+
# transitive package. And no extra terminal window - the command is printed instead.
|
|
256
253
|
activate_env(env_type, env_dir)
|
|
257
254
|
return # Stop here after venv setup
|
|
258
255
|
|
|
@@ -260,14 +257,14 @@ def install_requirements(env_type, env_dir, project_root):
|
|
|
260
257
|
if env_type == "conda":
|
|
261
258
|
conda_executable = find_conda_executable()
|
|
262
259
|
print("📦 Creating conda environment...")
|
|
263
|
-
|
|
260
|
+
if not os.path.exists(env_dir): # create_virtual_env() usually made it already
|
|
261
|
+
subprocess.run([conda_executable, "create", "-p", env_dir, "python=3.12", "-y"], check=True)
|
|
264
262
|
print("✅ Conda environment created successfully.")
|
|
265
263
|
|
|
266
264
|
# Use animated dependency installer for conda
|
|
267
265
|
from ntc.cli_enhanced import animate_dependency_install
|
|
268
266
|
pip_command = [conda_executable, "run", "-p", env_dir, "pip", "install", "-r", requirements_path]
|
|
269
267
|
animate_dependency_install(requirements_path, pip_command, "conda")
|
|
270
|
-
update_requirements_versioning(env_type, project_root)
|
|
271
268
|
activate_env(env_type, env_dir)
|
|
272
269
|
|
|
273
270
|
def get_pip_path(env_dir):
|
|
@@ -294,7 +291,10 @@ def get_pip_path(env_dir):
|
|
|
294
291
|
print("❌ pip still not found after ensurepip.")
|
|
295
292
|
return None
|
|
296
293
|
|
|
297
|
-
|
|
294
|
+
# The initial migration ships with the app, so a new project's first `migrate` creates the users
|
|
295
|
+
# table - no makemigrations step to know about.
|
|
296
|
+
AUTH_APP_FILES = ('apps.py', 'models.py', 'serializers.py', 'views.py', 'urls.py', 'admin.py', 'tests.py',
|
|
297
|
+
os.path.join('migrations', '0001_initial.py'))
|
|
298
298
|
|
|
299
299
|
|
|
300
300
|
def _auth_variables(with_auth):
|