ntc-dev-kit 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. ntc/__init__.py +5 -0
  2. ntc/app_creator.py +296 -0
  3. ntc/cli.py +4 -0
  4. ntc/cli_enhanced.py +820 -0
  5. ntc/composer/__init__.py +0 -0
  6. ntc/composer/main.py +443 -0
  7. ntc/deployment/__init__.py +0 -0
  8. ntc/templates/__init__.py +2 -0
  9. ntc/templates/auth_app/__init__.py +0 -0
  10. ntc/templates/auth_app/admin.py +24 -0
  11. ntc/templates/auth_app/apps.py +6 -0
  12. ntc/templates/auth_app/models.py +30 -0
  13. ntc/templates/auth_app/serializers.py +101 -0
  14. ntc/templates/auth_app/urls.py +19 -0
  15. ntc/templates/auth_app/views.py +175 -0
  16. ntc/templates/drf_structure/__init__.py +1 -0
  17. ntc/templates/drf_structure/drf_structure.md +83 -0
  18. ntc/templates/drf_structure/main.py +389 -0
  19. ntc/templates/drf_structure/structure.json +126 -0
  20. ntc/templates/drf_structure/templates/.entry/start_core_backend.sh +37 -0
  21. ntc/templates/drf_structure/templates/.entry/start_tasks_backend.sh +30 -0
  22. ntc/templates/drf_structure/templates/CLAUDE.md +194 -0
  23. ntc/templates/drf_structure/templates/README.md +117 -0
  24. ntc/templates/drf_structure/templates/apps/app_admin.py +3 -0
  25. ntc/templates/drf_structure/templates/apps/app_apps.py +6 -0
  26. ntc/templates/drf_structure/templates/apps/app_models.py +4 -0
  27. ntc/templates/drf_structure/templates/apps/app_urls.py +8 -0
  28. ntc/templates/drf_structure/templates/apps/app_views.py +6 -0
  29. ntc/templates/drf_structure/templates/apps/common_apps.py +6 -0
  30. ntc/templates/drf_structure/templates/apps/common_models.py +8 -0
  31. ntc/templates/drf_structure/templates/config/gunicorn_config.py +9 -0
  32. ntc/templates/drf_structure/templates/config/http.conf +33 -0
  33. ntc/templates/drf_structure/templates/core/base_model.py +9 -0
  34. ntc/templates/drf_structure/templates/core/formatter.py +5 -0
  35. ntc/templates/drf_structure/templates/core/logger.py +8 -0
  36. ntc/templates/drf_structure/templates/core/pagination.py +6 -0
  37. ntc/templates/drf_structure/templates/core/response_wrapper.py +7 -0
  38. ntc/templates/drf_structure/templates/core/services/azure/email/backend.py +108 -0
  39. ntc/templates/drf_structure/templates/core/services/azure/email/client.py +296 -0
  40. ntc/templates/drf_structure/templates/core/services/azure/email/notifier.py +102 -0
  41. ntc/templates/drf_structure/templates/core/services/object_storage.py +285 -0
  42. ntc/templates/drf_structure/templates/django_project/asgi.py +5 -0
  43. ntc/templates/drf_structure/templates/django_project/celery.py +8 -0
  44. ntc/templates/drf_structure/templates/django_project/dev_settings.py +2 -0
  45. ntc/templates/drf_structure/templates/django_project/django_settings.txt +322 -0
  46. ntc/templates/drf_structure/templates/django_project/management_command.py +114 -0
  47. ntc/templates/drf_structure/templates/django_project/prod_settings.py +3 -0
  48. ntc/templates/drf_structure/templates/django_project/schema.py +7 -0
  49. ntc/templates/drf_structure/templates/django_project/urls.py +6 -0
  50. ntc/templates/drf_structure/templates/django_project/wsgi.py +5 -0
  51. ntc/templates/drf_structure/templates/docker/docker-compose.yml +11 -0
  52. ntc/templates/drf_structure/templates/knowledge/knowledge_description.md +201 -0
  53. ntc/templates/drf_structure/templates/knowledge/knowledge_design_pattern.md +722 -0
  54. ntc/templates/drf_structure/templates/knowledge/knowledge_structure.md +151 -0
  55. ntc/templates/drf_structure/templates/root/README.md +307 -0
  56. ntc/templates/drf_structure/templates/root/django_env.txt +98 -0
  57. ntc/templates/drf_structure/templates/root/django_requirements.txt +24 -0
  58. ntc/templates/drf_structure/templates/root/gitignore.txt +6 -0
  59. ntc/templates/drf_structure/templates/root/manage.py +11 -0
  60. ntc/templates/flutter/.gitignore +44 -0
  61. ntc/templates/flutter/.knowledge/knowledge_description.md +215 -0
  62. ntc/templates/flutter/.knowledge/knowledge_design_pattern.md +310 -0
  63. ntc/templates/flutter/.knowledge/knowledge_structure.md +83 -0
  64. ntc/templates/flutter/CLAUDE.md +190 -0
  65. ntc/templates/flutter/__init__.py +0 -0
  66. ntc/templates/flutter/analysis_options.yaml +9 -0
  67. ntc/templates/flutter/main.py +187 -0
  68. ntc/templates/flutter/pubspec.yaml +65 -0
  69. ntc/templates/flutter/structure.json +51 -0
  70. ntc/templates/nextjs/.env.example +10 -0
  71. ntc/templates/nextjs/.gitignore +36 -0
  72. ntc/templates/nextjs/CLAUDE.md +181 -0
  73. ntc/templates/nextjs/README.md +94 -0
  74. ntc/templates/nextjs/__init__.py +0 -0
  75. ntc/templates/nextjs/knowledge/knowledge_description.md +208 -0
  76. ntc/templates/nextjs/knowledge/knowledge_design_pattern.md +460 -0
  77. ntc/templates/nextjs/knowledge/knowledge_structure.md +75 -0
  78. ntc/templates/nextjs/main.py +224 -0
  79. ntc/templates/nextjs/package.json +25 -0
  80. ntc/templates/nextjs/src/app/globals.css +26 -0
  81. ntc/templates/nextjs/src/app/layout.tsx +59 -0
  82. ntc/templates/nextjs/src/app/page.tsx +21 -0
  83. ntc/templates/nextjs/src/components/Header.tsx +16 -0
  84. ntc/templates/nextjs/src/services/api.ts +81 -0
  85. ntc/templates/nextjs/src/utils/constants.ts +1 -0
  86. ntc/templates/nextjs/structure.json +32 -0
  87. ntc/templates/nextjs/tsconfig.json +27 -0
  88. ntc/templates/react_admin/.env.example +1 -0
  89. ntc/templates/react_admin/.gitignore +10 -0
  90. ntc/templates/react_admin/CLAUDE.md +210 -0
  91. ntc/templates/react_admin/README.md +72 -0
  92. ntc/templates/react_admin/__init__.py +0 -0
  93. ntc/templates/react_admin/index.html +13 -0
  94. ntc/templates/react_admin/knowledge/knowledge_description.md +202 -0
  95. ntc/templates/react_admin/knowledge/knowledge_design_pattern.md +448 -0
  96. ntc/templates/react_admin/knowledge/knowledge_structure.md +97 -0
  97. ntc/templates/react_admin/main.py +208 -0
  98. ntc/templates/react_admin/package.json +35 -0
  99. ntc/templates/react_admin/src/App.tsx +60 -0
  100. ntc/templates/react_admin/src/components/ProtectedRoute.tsx +16 -0
  101. ntc/templates/react_admin/src/components/Sidebar.tsx +90 -0
  102. ntc/templates/react_admin/src/components/TopNav.tsx +44 -0
  103. ntc/templates/react_admin/src/context/AuthContext.tsx +107 -0
  104. ntc/templates/react_admin/src/context/ThemeContext.tsx +34 -0
  105. ntc/templates/react_admin/src/context/WorkspaceContext.tsx +28 -0
  106. ntc/templates/react_admin/src/hooks/useApi.ts +39 -0
  107. ntc/templates/react_admin/src/index.css +34 -0
  108. ntc/templates/react_admin/src/layouts/AuthLayout.tsx +23 -0
  109. ntc/templates/react_admin/src/layouts/DashboardLayout.tsx +24 -0
  110. ntc/templates/react_admin/src/main.tsx +5 -0
  111. ntc/templates/react_admin/src/pages/DashboardPage.tsx +10 -0
  112. ntc/templates/react_admin/src/pages/auth/LoginPage.tsx +79 -0
  113. ntc/templates/react_admin/src/pages/auth/RegisterPage.tsx +93 -0
  114. ntc/templates/react_admin/src/services/api.service.ts +44 -0
  115. ntc/templates/react_admin/src/services/base.service.ts +193 -0
  116. ntc/templates/react_admin/structure.json +52 -0
  117. ntc/templates/react_admin/tsconfig.app.json +25 -0
  118. ntc/templates/react_admin/tsconfig.json +7 -0
  119. ntc/templates/react_admin/tsconfig.node.json +19 -0
  120. ntc/templates/react_admin/vite.config.ts +13 -0
  121. ntc/templates/react_structure/CLAUDE.md +176 -0
  122. ntc/templates/react_structure/__init__.py +1 -0
  123. ntc/templates/react_structure/index.css +21 -0
  124. ntc/templates/react_structure/index.html +13 -0
  125. ntc/templates/react_structure/knowledge/knowledge_description.md +170 -0
  126. ntc/templates/react_structure/knowledge/knowledge_design_pattern.md +411 -0
  127. ntc/templates/react_structure/knowledge/knowledge_structure.md +74 -0
  128. ntc/templates/react_structure/main.py +217 -0
  129. ntc/templates/react_structure/package.json +32 -0
  130. ntc/templates/react_structure/src/App.tsx +63 -0
  131. ntc/templates/react_structure/src/components/Header.tsx +51 -0
  132. ntc/templates/react_structure/src/main.tsx +5 -0
  133. ntc/templates/react_structure/src/services/api.ts +90 -0
  134. ntc/templates/react_structure/src/utils/constants.ts +1 -0
  135. ntc/templates/react_structure/structure.json +65 -0
  136. ntc/templates/react_structure/tsconfig.app.json +25 -0
  137. ntc/templates/react_structure/tsconfig.json +7 -0
  138. ntc/templates/react_structure/tsconfig.node.json +19 -0
  139. ntc/templates/react_structure/vite.config.ts +12 -0
  140. ntc/utils/__init__.py +1 -0
  141. ntc/utils/environment.py +67 -0
  142. ntc/utils/output.py +41 -0
  143. ntc_dev_kit-1.0.0.dist-info/METADATA +188 -0
  144. ntc_dev_kit-1.0.0.dist-info/RECORD +148 -0
  145. ntc_dev_kit-1.0.0.dist-info/WHEEL +5 -0
  146. ntc_dev_kit-1.0.0.dist-info/entry_points.txt +2 -0
  147. ntc_dev_kit-1.0.0.dist-info/licenses/LICENSE +21 -0
  148. ntc_dev_kit-1.0.0.dist-info/top_level.txt +1 -0
ntc/cli_enhanced.py ADDED
@@ -0,0 +1,820 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ import msvcrt
5
+ import time
6
+ from colorama import Fore, Back, Style, init
7
+ from ntc.templates.drf_structure.main import init_drf_project, init_drf_project_in_current_dir
8
+ from ntc.templates.react_structure.main import init_react_project, init_react_project_in_current_dir
9
+ from ntc.templates.react_admin.main import init_react_admin_project, init_react_admin_project_in_current_dir
10
+ from ntc.templates.nextjs.main import init_nextjs_project, init_nextjs_project_in_current_dir
11
+ from ntc.templates.flutter.main import init_flutter_project, init_flutter_project_in_current_dir
12
+ from ntc.composer.main import compose_project, compose_project_in_current_dir, start_services
13
+ from ntc.app_creator import create_app_structure
14
+
15
+ # Initialize colorama for cross-platform colored output
16
+ init(autoreset=True)
17
+
18
+ def print_banner():
19
+ """Display the clean NTC welcome banner."""
20
+ print(f"""
21
+ {Fore.CYAN}╔{'═' * 75}╗{Style.RESET_ALL}
22
+ {Fore.CYAN}║{' ' * 75}║{Style.RESET_ALL}
23
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}███╗ ██╗████████╗ ██████╗{' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
24
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}████╗ ██║╚══██╔══╝██╔════╝{' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
25
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}██╔██╗ ██║ ██║ ██║ {' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
26
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}██║╚██╗██║ ██║ ██║ {' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
27
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}██║ ╚████║ ██║ ╚██████╗{' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
28
+ {Fore.CYAN}║{' ' * 25}{Fore.YELLOW}{Style.BRIGHT}╚═╝ ╚═══╝ ╚═╝ ╚═════╝{' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
29
+ {Fore.CYAN}║{' ' * 75}║{Style.RESET_ALL}
30
+ {Fore.CYAN}║{' ' * 24}{Fore.GREEN}{Style.BRIGHT}🚀 NEXENT TOOLKIT CONSOLE 🚀{' ' * 23}{Fore.CYAN}║{Style.RESET_ALL}
31
+ {Fore.CYAN}║{' ' * 75}║{Style.RESET_ALL}
32
+ {Fore.CYAN}║{' ' * 16}{Fore.WHITE}The ultimate toolkit for API-driven development{' ' * 12}{Fore.CYAN}║{Style.RESET_ALL}
33
+ {Fore.CYAN}║{' ' * 75}║{Style.RESET_ALL}
34
+ {Fore.CYAN}║{' ' * 10}{Fore.GREEN}Backend:{Fore.WHITE} Django/DRF, Laravel {Fore.BLUE}Frontend:{Fore.WHITE} React, Angular, Vue {Fore.CYAN}{' ' * 5}║{Style.RESET_ALL}
35
+ {Fore.CYAN}║{' ' * 75}║{Style.RESET_ALL}
36
+ {Fore.CYAN}╚{'═' * 75}╝{Style.RESET_ALL}""")
37
+ print()
38
+
39
+ def print_welcome_message():
40
+ """Display a simple welcome message."""
41
+ print(f" {Fore.BLUE}💡 Use arrow keys to navigate • Press Enter to select • Esc to exit{Style.RESET_ALL}")
42
+ print()
43
+
44
+ def print_success(message):
45
+ """Print success message with green color and checkmark."""
46
+ print(f"{Fore.GREEN}✅ {message}{Style.RESET_ALL}")
47
+
48
+ def print_error(message):
49
+ """Print error message with red color and X mark."""
50
+ print(f"{Fore.RED}❌ {message}{Style.RESET_ALL}")
51
+
52
+ def print_warning(message):
53
+ """Print warning message with yellow color and warning sign."""
54
+ print(f"{Fore.YELLOW}⚠️ {message}{Style.RESET_ALL}")
55
+
56
+ def print_info(message):
57
+ """Print info message with blue color and info icon."""
58
+ print(f"{Fore.CYAN}ℹ️ {message}{Style.RESET_ALL}")
59
+
60
+ def print_question(message):
61
+ """Print question with bright white color and question mark."""
62
+ return input(f"{Fore.WHITE}{Style.BRIGHT}❓ {message}{Style.RESET_ALL}")
63
+
64
+ def clear_screen():
65
+ """Clear the terminal screen."""
66
+ os.system('cls' if os.name == 'nt' else 'clear')
67
+
68
+ def print_choice(number, description, selected=False):
69
+ """Print a numbered choice option with selection highlighting."""
70
+ if selected:
71
+ print(f"{Back.CYAN}{Fore.WHITE}{Style.BRIGHT} ► [{number}] {description} {Style.RESET_ALL}")
72
+ else:
73
+ print(f" {Fore.YELLOW}[{number}]{Style.RESET_ALL} {Fore.WHITE}{description}{Style.RESET_ALL}")
74
+
75
+ def print_menu_header(title, subtitle=""):
76
+ """Print an attractive menu header."""
77
+ width = 70
78
+ print(f"\n{Fore.CYAN}{'═' * width}{Style.RESET_ALL}")
79
+ print(f"{Fore.CYAN}║{' ' * ((width - len(title) - 2) // 2)}{Fore.YELLOW}{Style.BRIGHT}{title}{Fore.CYAN}{' ' * ((width - len(title) - 2) // 2)}║{Style.RESET_ALL}")
80
+ if subtitle:
81
+ print(f"{Fore.CYAN}║{' ' * ((width - len(subtitle) - 2) // 2)}{Fore.WHITE}{subtitle}{Fore.CYAN}{' ' * ((width - len(subtitle) - 2) // 2)}║{Style.RESET_ALL}")
82
+ print(f"{Fore.CYAN}{'═' * width}{Style.RESET_ALL}")
83
+
84
+ def print_navigation_help():
85
+ """Print navigation instructions."""
86
+ print(f"\n{Fore.MAGENTA}🎮 Navigation:{Style.RESET_ALL}")
87
+ print(f" {Fore.GREEN}↑/↓{Style.RESET_ALL} Navigate {Fore.GREEN}Enter{Style.RESET_ALL} Select {Fore.GREEN}Esc{Style.RESET_ALL} Exit")
88
+
89
+ def animate_loading(message, duration=1.5):
90
+ """Show an animated loading message."""
91
+ frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
92
+ end_time = time.time() + duration
93
+
94
+ while time.time() < end_time:
95
+ for frame in frames:
96
+ if time.time() >= end_time:
97
+ break
98
+ print(f"\r{Fore.CYAN}{frame} {message}{Style.RESET_ALL}", end="", flush=True)
99
+ time.sleep(0.1)
100
+
101
+ print(f"\r{Fore.GREEN}✅ {message} Complete!{Style.RESET_ALL}")
102
+ time.sleep(0.5)
103
+
104
+ def animate_progress(message, steps=None, duration=3.0):
105
+ """Show progress animation with percentage on the same line."""
106
+ frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
107
+
108
+ if steps:
109
+ # Step-based progress
110
+ for i, step in enumerate(steps, 1):
111
+ progress = int((i / len(steps)) * 100)
112
+ for j in range(10): # Show animation for each step
113
+ frame = frames[j % len(frames)]
114
+ print(f"\r{Fore.CYAN}{frame} {message}: {step} {Fore.YELLOW}[{progress}%]{Style.RESET_ALL}", end="", flush=True)
115
+ time.sleep(0.1)
116
+ print(f"\r{Fore.GREEN}✅ {message} Complete! {Fore.YELLOW}[100%]{Style.RESET_ALL}")
117
+ else:
118
+ # Time-based progress
119
+ start_time = time.time()
120
+ end_time = start_time + duration
121
+
122
+ while time.time() < end_time:
123
+ elapsed = time.time() - start_time
124
+ progress = int((elapsed / duration) * 100)
125
+ frame = frames[int(elapsed * 10) % len(frames)]
126
+
127
+ print(f"\r{Fore.CYAN}{frame} {message} {Fore.YELLOW}[{progress}%]{Style.RESET_ALL}", end="", flush=True)
128
+ time.sleep(0.1)
129
+
130
+ print(f"\r{Fore.GREEN}✅ {message} Complete! {Fore.YELLOW}[100%]{Style.RESET_ALL}")
131
+
132
+ print() # New line after completion
133
+
134
+ def animate_dependency_install(requirements_path=None, pip_command=None, env_type="system"):
135
+ """Show real dependency installation with progress animation."""
136
+ import subprocess
137
+ import threading
138
+
139
+ if not requirements_path or not os.path.exists(requirements_path):
140
+ # Fallback to simulation if no requirements file
141
+ dependencies = [
142
+ "Resolving dependencies",
143
+ "Downloading packages",
144
+ "Installing Django",
145
+ "Installing DRF",
146
+ "Installing Celery",
147
+ "Installing CORS headers",
148
+ "Configuring environment",
149
+ "Setting up database",
150
+ "Creating migrations",
151
+ "Finalizing setup"
152
+ ]
153
+
154
+ print(f"\n{Fore.MAGENTA}📦 Installing Dependencies{Style.RESET_ALL}")
155
+
156
+ for i, dep in enumerate(dependencies, 1):
157
+ progress = int((i / len(dependencies)) * 100)
158
+
159
+ # Show animation for each dependency
160
+ for j in range(5): # 5 animation cycles per dependency
161
+ frame = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"][j % 10]
162
+ # Clear line and print new content
163
+ print(f"\r{' ' * 80}\r{Fore.CYAN}{frame} {dep}... {Fore.YELLOW}[{progress}%]{Style.RESET_ALL}", end="", flush=True)
164
+ time.sleep(0.2)
165
+
166
+ print(f"\r{' ' * 80}\r{Fore.GREEN}✅ All dependencies installed successfully! {Fore.YELLOW}[100%]{Style.RESET_ALL}")
167
+ print()
168
+ return
169
+
170
+ # Real dependency installation with animation
171
+ print(f"\n{Fore.MAGENTA}📦 Installing Dependencies{Style.RESET_ALL}")
172
+
173
+ # Determine the pip command to use
174
+ if pip_command is None:
175
+ # Default to system pip
176
+ pip_command = [sys.executable, "-m", "pip", "install", "-r", requirements_path]
177
+
178
+ # Animation state
179
+ animation_running = True
180
+ install_complete = False
181
+ install_success = False
182
+ error_message = ""
183
+
184
+ def run_pip_install():
185
+ nonlocal install_complete, install_success, error_message
186
+ try:
187
+ # Run pip install with suppressed output
188
+ result = subprocess.run(
189
+ pip_command,
190
+ capture_output=True,
191
+ text=True,
192
+ check=True
193
+ )
194
+ install_success = True
195
+ except subprocess.CalledProcessError as e:
196
+ install_success = False
197
+ error_message = str(e)
198
+ finally:
199
+ install_complete = True
200
+
201
+ # Start installation in background thread
202
+ install_thread = threading.Thread(target=run_pip_install)
203
+ install_thread.start()
204
+
205
+ # Show animation while installation runs
206
+ frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
207
+ frame_index = 0
208
+
209
+ while not install_complete:
210
+ frame = frames[frame_index % len(frames)]
211
+ # Clear line completely before writing new content
212
+ env_msg = f" ({env_type} environment)" if env_type != "system" else ""
213
+ print(f"\r{' ' * 80}\r{Fore.CYAN}{frame} Installing packages{env_msg}...{Style.RESET_ALL}", end="", flush=True)
214
+ time.sleep(0.1)
215
+ frame_index += 1
216
+
217
+ # Wait for thread to complete
218
+ install_thread.join()
219
+
220
+ # Show final result
221
+ if install_success:
222
+ print(f"\r{' ' * 80}\r{Fore.GREEN}✅ All dependencies installed successfully!{Style.RESET_ALL}")
223
+ else:
224
+ print(f"\r{' ' * 80}\r{Fore.RED}❌ Failed to install dependencies: {error_message}{Style.RESET_ALL}")
225
+ print(f"{Fore.YELLOW}💡 You can manually install later with: pip install -r requirements.txt{Style.RESET_ALL}")
226
+
227
+ print()
228
+
229
+ def get_key():
230
+ """Get a single keypress from user."""
231
+ if os.name == 'nt': # Windows
232
+ key = msvcrt.getch()
233
+ if key == b'\xe0': # Arrow keys on Windows
234
+ key = msvcrt.getch()
235
+ if key == b'H': # Up arrow
236
+ return 'up'
237
+ elif key == b'P': # Down arrow
238
+ return 'down'
239
+ elif key == b'\r': # Enter
240
+ return 'enter'
241
+ elif key == b'\x1b': # Escape
242
+ return 'escape'
243
+ else:
244
+ return key.decode('utf-8', errors='ignore')
245
+ else: # Unix/Linux/Mac
246
+ import termios, tty
247
+ fd = sys.stdin.fileno()
248
+ old_settings = termios.tcgetattr(fd)
249
+ try:
250
+ tty.setraw(sys.stdin.fileno())
251
+ key = sys.stdin.read(1)
252
+ if key == '\x1b': # Escape sequence
253
+ key += sys.stdin.read(2)
254
+ if key == '\x1b[A': # Up arrow
255
+ return 'up'
256
+ elif key == '\x1b[B': # Down arrow
257
+ return 'down'
258
+ else:
259
+ return 'escape'
260
+ elif key == '\r' or key == '\n': # Enter
261
+ return 'enter'
262
+ else:
263
+ return key
264
+ finally:
265
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
266
+
267
+ def interactive_menu(title, options, subtitle=""):
268
+ """Display an interactive menu with keyboard navigation."""
269
+ selected = 0
270
+
271
+ while True:
272
+ clear_screen()
273
+ print_banner()
274
+ print_menu_header(title, subtitle)
275
+
276
+ # Display options
277
+ for i, option in enumerate(options):
278
+ print_choice(i + 1, option['label'], selected == i)
279
+
280
+ print_navigation_help()
281
+
282
+ # Get user input
283
+ key = get_key()
284
+
285
+ if key == 'up':
286
+ selected = (selected - 1) % len(options)
287
+ elif key == 'down':
288
+ selected = (selected + 1) % len(options)
289
+ elif key == 'enter':
290
+ animate_loading(f"Selecting {options[selected]['label']}")
291
+ return options[selected]['value']
292
+ elif key == 'escape':
293
+ print(f"\n{Fore.YELLOW}👋 Goodbye!{Style.RESET_ALL}")
294
+ sys.exit(0)
295
+ elif key.isdigit():
296
+ # Allow direct number selection
297
+ num = int(key) - 1
298
+ if 0 <= num < len(options):
299
+ selected = num
300
+
301
+ def get_project_type():
302
+ """Ask user to choose between frontend or backend project."""
303
+ options = [
304
+ {'label': '🔧 Backend (API Server)', 'value': 'backend'},
305
+ {'label': '🎨 Frontend (Client Application)', 'value': 'frontend'}
306
+ ]
307
+ return interactive_menu("PROJECT TYPE SELECTION", options, "Choose your project architecture")
308
+
309
+ def get_backend_technology():
310
+ """Ask user to choose backend technology."""
311
+ options = [
312
+ {'label': '🐍 Django REST Framework (Python)', 'value': 'django'},
313
+ {'label': '🐘 Laravel (PHP) - Coming Soon!', 'value': 'laravel'}
314
+ ]
315
+ result = interactive_menu("BACKEND TECHNOLOGY", options, "Select your backend framework")
316
+
317
+ if result == 'laravel':
318
+ print_warning("Laravel support is coming soon! Using Django for now.")
319
+ return 'django'
320
+ return result
321
+
322
+ def get_frontend_technology():
323
+ """Ask user to choose frontend technology."""
324
+ options = [
325
+ {'label': '🌐 Next.js (TypeScript + SEO Optimized)', 'value': 'nextjs'},
326
+ {'label': '📱 Flutter (Dart + Cross-Platform)', 'value': 'flutter'},
327
+ {'label': '⚛️ React Admin Dashboard (TypeScript + Vite)', 'value': 'react-admin'},
328
+ {'label': '⚛️ React (TypeScript + Vite)', 'value': 'react'},
329
+ {'label': '🅰️ Angular (TypeScript) - Coming Soon!', 'value': 'angular'},
330
+ {'label': '💚 Vue.js (TypeScript) - Coming Soon!', 'value': 'vue'}
331
+ ]
332
+ result = interactive_menu("FRONTEND TECHNOLOGY", options, "Select your frontend framework")
333
+
334
+ if result in ['angular', 'vue']:
335
+ print_warning(f"{result.title()} support is coming soon! Using React for now.")
336
+ return 'react'
337
+ return result
338
+
339
+ def get_project_name():
340
+ """Get project name with enhanced input."""
341
+ clear_screen()
342
+ print_banner()
343
+ print_welcome_message()
344
+ print_menu_header("PROJECT SETUP", "Enter your project details")
345
+
346
+ print(f"\n{Fore.CYAN}📝 Project Name:{Style.RESET_ALL}")
347
+ print(f" {Fore.WHITE}• Use lowercase letters, numbers, and underscores{Style.RESET_ALL}")
348
+ print(f" {Fore.WHITE}• Type '.' to use current directory name{Style.RESET_ALL}")
349
+
350
+ project_name = print_question("Enter your project name: ").strip()
351
+ if not project_name:
352
+ print_error("Project name cannot be empty!")
353
+ time.sleep(2)
354
+ return get_project_name()
355
+
356
+ return project_name
357
+
358
+ def get_project_path(project_name, use_current_dir=False):
359
+ """Get project path with enhanced input."""
360
+ if use_current_dir:
361
+ return os.path.dirname(os.getcwd())
362
+
363
+ clear_screen()
364
+ print_banner()
365
+ print_menu_header("PROJECT LOCATION", "Choose where to create your project")
366
+
367
+ current_dir = os.getcwd()
368
+ print(f"\n{Fore.CYAN}📁 Current Directory:{Style.RESET_ALL}")
369
+ print(f" {Fore.WHITE}{current_dir}{Style.RESET_ALL}")
370
+
371
+ options = [
372
+ {'label': f'📂 Use current directory ({current_dir})', 'value': 'current'},
373
+ {'label': '📁 Choose custom path', 'value': 'custom'}
374
+ ]
375
+
376
+ choice = interactive_menu("PROJECT LOCATION", options, "Where should we create your project?")
377
+
378
+ if choice == 'current':
379
+ return current_dir
380
+ else:
381
+ custom_path = print_question(f"Enter custom path (default: {current_dir}): ").strip()
382
+ return custom_path if custom_path else current_dir
383
+
384
+ def show_project_summary(project_name, project_type, technology, project_path):
385
+ """Show project configuration summary."""
386
+ clear_screen()
387
+ print_banner()
388
+ print_menu_header("PROJECT SUMMARY", "Review your configuration")
389
+
390
+ print(f"\n{Fore.GREEN}✨ Project Configuration:{Style.RESET_ALL}")
391
+ print(f" {Fore.CYAN}📛 Name:{Style.RESET_ALL} {Fore.WHITE}{project_name}{Style.RESET_ALL}")
392
+ print(f" {Fore.CYAN}🏗️ Type:{Style.RESET_ALL} {Fore.WHITE}{project_type.title()}{Style.RESET_ALL}")
393
+ print(f" {Fore.CYAN}🔧 Technology:{Style.RESET_ALL} {Fore.WHITE}{technology.title()}{Style.RESET_ALL}")
394
+ print(f" {Fore.CYAN}📁 Path:{Style.RESET_ALL} {Fore.WHITE}{project_path}{Style.RESET_ALL}")
395
+
396
+ options = [
397
+ {'label': '🚀 Create Project', 'value': 'create'},
398
+ {'label': '🔄 Start Over', 'value': 'restart'},
399
+ {'label': '❌ Cancel', 'value': 'cancel'}
400
+ ]
401
+
402
+ return interactive_menu("CONFIRM CREATION", options, "Ready to create your project?")
403
+
404
+ def interactive_init(preset_project_type=None, preset_technology=None):
405
+ """Interactive project initialization with enhanced UI."""
406
+ while True:
407
+ # Get project name
408
+ project_name = get_project_name()
409
+
410
+ # Handle '.' as current directory shorthand
411
+ use_current_dir = False
412
+ if project_name == ".":
413
+ current_dir = os.getcwd()
414
+ project_name = os.path.basename(current_dir)
415
+ use_current_dir = True
416
+ animate_loading(f"Using current directory name: '{project_name}'")
417
+
418
+ # Get project type
419
+ if preset_project_type:
420
+ project_type = preset_project_type
421
+ else:
422
+ project_type = get_project_type()
423
+
424
+ # Get technology based on project type
425
+ if preset_technology:
426
+ technology = preset_technology
427
+ else:
428
+ if project_type == "backend":
429
+ technology = get_backend_technology()
430
+ else:
431
+ technology = get_frontend_technology()
432
+
433
+ # Get project path
434
+ project_path = get_project_path(project_name, use_current_dir)
435
+
436
+ # Show summary and get confirmation
437
+ action = show_project_summary(project_name, project_type, technology, project_path)
438
+
439
+ if action == 'create':
440
+ break
441
+ elif action == 'restart':
442
+ continue
443
+ else: # cancel
444
+ print(f"\n{Fore.YELLOW}👋 Project creation cancelled. Goodbye!{Style.RESET_ALL}")
445
+ sys.exit(0)
446
+
447
+ # Create the project with enhanced feedback
448
+ animate_loading("Initializing project structure")
449
+
450
+ # Determine final project location
451
+ if use_current_dir:
452
+ final_project_path = os.getcwd()
453
+ else:
454
+ final_project_path = os.path.join(project_path, project_name)
455
+
456
+ # Initialize project with enhanced feedback
457
+ clear_screen()
458
+ print_banner()
459
+ print_menu_header("CREATING PROJECT", f"Setting up {project_name}")
460
+
461
+ print(f"\n{Fore.GREEN}🚀 Initializing {project_type} project with {technology}...{Style.RESET_ALL}")
462
+
463
+ # Execute project creation first (to create requirements.txt)
464
+ try:
465
+ if technology == "django":
466
+ if use_current_dir:
467
+ init_drf_project_in_current_dir(project_name)
468
+ else:
469
+ init_drf_project(project_path, project_name)
470
+
471
+ # Now show animated dependency installation with real requirements.txt
472
+ requirements_path = os.path.join(final_project_path, "requirements.txt")
473
+ if os.path.exists(requirements_path):
474
+ animate_dependency_install(requirements_path)
475
+ elif technology == "react":
476
+ if use_current_dir:
477
+ init_react_project_in_current_dir(project_name)
478
+ else:
479
+ init_react_project(project_path, project_name)
480
+ elif technology == "react-admin":
481
+ if use_current_dir:
482
+ init_react_admin_project_in_current_dir(project_name)
483
+ else:
484
+ init_react_admin_project(project_path, project_name)
485
+ elif technology == "nextjs":
486
+ if use_current_dir:
487
+ init_nextjs_project_in_current_dir(project_name)
488
+ else:
489
+ init_nextjs_project(project_path, project_name)
490
+ elif technology == "flutter":
491
+ if use_current_dir:
492
+ init_flutter_project_in_current_dir(project_name)
493
+ else:
494
+ init_flutter_project(project_path, project_name)
495
+ else:
496
+ print_error(f"Technology '{technology}' is not yet implemented!")
497
+ sys.exit(1)
498
+
499
+ # Ask about authentication app for Django projects
500
+ if technology == "django":
501
+ if ask_for_auth_app():
502
+ create_authentication_app(final_project_path, project_name)
503
+
504
+ # Success screen
505
+ show_success_screen(project_name, project_type, technology, final_project_path)
506
+
507
+ except Exception as e:
508
+ print_error(f"Project creation failed: {str(e)}")
509
+ sys.exit(1)
510
+
511
+ def ask_for_auth_app():
512
+ """Ask user if they want to create an authentication app."""
513
+ clear_screen()
514
+ print_banner()
515
+ print_menu_header("AUTHENTICATION SETUP", "Add a dedicated authentication app?")
516
+
517
+ print(f"\n{Fore.CYAN}🔐 Authentication App Features:{Style.RESET_ALL}")
518
+ print(f" {Fore.WHITE}• Custom User model with AbstractUser{Style.RESET_ALL}")
519
+ print(f" {Fore.WHITE}• JWT Authentication (login, register, refresh){Style.RESET_ALL}")
520
+ print(f" {Fore.WHITE}• Profile management (me, update-profile){Style.RESET_ALL}")
521
+ print(f" {Fore.WHITE}• Password management (change, reset){Style.RESET_ALL}")
522
+ print(f" {Fore.WHITE}• Ready-to-use serializers and views{Style.RESET_ALL}")
523
+
524
+ options = [
525
+ {'label': '✅ Yes, create authentication app', 'value': True},
526
+ {'label': '❌ No, skip authentication setup', 'value': False}
527
+ ]
528
+
529
+ return interactive_menu("AUTHENTICATION CHOICE", options, "Would you like to add authentication?")
530
+
531
+ def create_authentication_app(project_path, project_name):
532
+ """Create a complete authentication app with User model, serializers, and views."""
533
+ animate_loading("Creating authentication app", 1.0)
534
+
535
+ # Create authentication app directory inside apps/
536
+ auth_app_path = os.path.join(project_path, "apps", "authentication")
537
+ os.makedirs(auth_app_path, exist_ok=True)
538
+
539
+ # Create __init__.py
540
+ with open(os.path.join(auth_app_path, "__init__.py"), "w") as f:
541
+ f.write("")
542
+
543
+ # Copy template files from auth_app templates directory
544
+ template_dir = os.path.join(os.path.dirname(__file__), "templates", "auth_app")
545
+
546
+ template_files = {
547
+ 'apps.py': 'apps.py',
548
+ 'models.py': 'models.py',
549
+ 'serializers.py': 'serializers.py',
550
+ 'views.py': 'views.py',
551
+ 'urls.py': 'urls.py',
552
+ 'admin.py': 'admin.py',
553
+ }
554
+
555
+ created_files = []
556
+ for dest_file, template_file in template_files.items():
557
+ template_path = os.path.join(template_dir, template_file)
558
+ if os.path.exists(template_path):
559
+ with open(template_path, 'r', encoding='utf-8') as f:
560
+ content = f.read()
561
+ dest_path = os.path.join(auth_app_path, dest_file)
562
+ with open(dest_path, 'w', encoding='utf-8') as f:
563
+ f.write(content)
564
+ created_files.append(dest_file)
565
+ else:
566
+ print_error(f"Template file not found: {template_path}")
567
+
568
+ # Update main project settings and URLs
569
+ update_project_for_auth(project_path, project_name)
570
+
571
+ animate_loading("Authentication app created successfully", 1.0)
572
+
573
+ # Print confirmation that persists through screen clears
574
+ print_success(f"Authentication app created at: apps/authentication/")
575
+ print_info(f"Files created: {', '.join(created_files)}")
576
+ print_info(f"Settings updated: INSTALLED_APPS + 'apps.authentication'")
577
+ print_info(f"URLs updated: path('auth/', include('apps.authentication.urls'))")
578
+
579
+ def update_project_for_auth(project_path, project_name):
580
+ """Update main project settings and URLs to include authentication app."""
581
+ # Update settings/base.py (generated projects use settings/base.py, not settings.py)
582
+ settings_path = os.path.join(project_path, project_name, "settings", "base.py")
583
+ if os.path.exists(settings_path):
584
+ with open(settings_path, "r") as f:
585
+ settings_content = f.read()
586
+
587
+ # Add authentication app to INSTALLED_APPS
588
+ if "'apps.authentication'," not in settings_content:
589
+ settings_content = settings_content.replace(
590
+ "INSTALLED_APPS = [",
591
+ "INSTALLED_APPS = [\n 'apps.authentication',"
592
+ )
593
+
594
+ # Add AUTH_USER_MODEL setting
595
+ if "AUTH_USER_MODEL" not in settings_content:
596
+ settings_content += "\n\n# Custom User Model\nAUTH_USER_MODEL = 'apps.authentication.User'\n"
597
+
598
+ # Add email settings placeholder
599
+ if "EMAIL_BACKEND" not in settings_content:
600
+ settings_content += """
601
+ # Email Settings (configure for production)
602
+ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
603
+ DEFAULT_FROM_EMAIL = 'noreply@yourproject.com'
604
+ FRONTEND_URL = 'http://localhost:3000' # Update with your frontend URL
605
+ """
606
+
607
+ with open(settings_path, "w") as f:
608
+ f.write(settings_content)
609
+
610
+ # Update main URLs
611
+ main_urls_path = os.path.join(project_path, project_name, "urls.py")
612
+ if os.path.exists(main_urls_path):
613
+ with open(main_urls_path, "r") as f:
614
+ urls_content = f.read()
615
+
616
+ # Add authentication URLs
617
+ if "path('auth/', include('apps.authentication.urls'))," not in urls_content:
618
+ # Add include import if not present
619
+ if "from django.urls import path, include" not in urls_content:
620
+ urls_content = urls_content.replace(
621
+ "from django.urls import path",
622
+ "from django.urls import path, include"
623
+ )
624
+
625
+ # Add auth URL pattern
626
+ urls_content = urls_content.replace(
627
+ "urlpatterns = [",
628
+ "urlpatterns = [\n path('auth/', include('apps.authentication.urls')),"
629
+ )
630
+
631
+ with open(main_urls_path, "w") as f:
632
+ f.write(urls_content)
633
+
634
+ def show_success_screen(project_name, project_type, technology, project_path):
635
+ """Show project creation success screen."""
636
+ clear_screen()
637
+
638
+ # Special success banner
639
+ print(f"\n{Fore.GREEN}{'▄' * 80}{Style.RESET_ALL}")
640
+ print(f"{Fore.GREEN}{'█' * 80}{Style.RESET_ALL}")
641
+ print(f"{Fore.GREEN}█{' ' * 78}█{Style.RESET_ALL}")
642
+ print(f"{Fore.GREEN}█{' ' * 25}🎉 PROJECT CREATED! 🎉{' ' * 26}█{Style.RESET_ALL}")
643
+ print(f"{Fore.GREEN}█{' ' * 78}█{Style.RESET_ALL}")
644
+ print(f"{Fore.GREEN}█{' ' * 15}{Fore.WHITE}🚀 {project_name} is ready for development! 🚀{' ' * 15}{Fore.GREEN}█{Style.RESET_ALL}")
645
+ print(f"{Fore.GREEN}█{' ' * 78}█{Style.RESET_ALL}")
646
+ print(f"{Fore.GREEN}{'█' * 80}{Style.RESET_ALL}")
647
+ print(f"{Fore.GREEN}{'▀' * 80}{Style.RESET_ALL}")
648
+ print()
649
+
650
+ # Check if authentication app was created
651
+ auth_app_exists = os.path.exists(os.path.join(project_path, "apps", "authentication"))
652
+
653
+ # Project details
654
+ print(f"\n{Fore.CYAN}📋 Project Details:{Style.RESET_ALL}")
655
+ print(f" {Fore.WHITE}📛 Name: {Fore.YELLOW}{project_name}{Style.RESET_ALL}")
656
+ print(f" {Fore.WHITE}🏗️ Type: {Fore.YELLOW}{project_type.title()}{Style.RESET_ALL}")
657
+ print(f" {Fore.WHITE}🔧 Tech: {Fore.YELLOW}{technology.title()}{Style.RESET_ALL}")
658
+ print(f" {Fore.WHITE}📁 Path: {Fore.YELLOW}{project_path}{Style.RESET_ALL}")
659
+ if auth_app_exists:
660
+ print(f" {Fore.WHITE}🔐 Auth: {Fore.GREEN}✅ Authentication app included{Style.RESET_ALL}")
661
+
662
+ # Next steps
663
+ print(f"\n{Fore.MAGENTA}🚀 Next Steps:{Style.RESET_ALL}")
664
+ if technology == "django":
665
+ print(f" {Fore.GREEN}1.{Style.RESET_ALL} {Fore.WHITE}cd {project_name}{Style.RESET_ALL}")
666
+ print(f" {Fore.GREEN}2.{Style.RESET_ALL} {Fore.WHITE}python manage.py runserver{Style.RESET_ALL}")
667
+ print(f" {Fore.GREEN}3.{Style.RESET_ALL} {Fore.WHITE}Visit http://127.0.0.1:8000/docs/ for API docs{Style.RESET_ALL}")
668
+ print(f" {Fore.GREEN}4.{Style.RESET_ALL} {Fore.WHITE}Use 'ntc create app <name>' to add new apps{Style.RESET_ALL}")
669
+ elif technology == "nextjs":
670
+ print(f" {Fore.GREEN}1.{Style.RESET_ALL} {Fore.WHITE}cd {project_name}{Style.RESET_ALL}")
671
+ print(f" {Fore.GREEN}2.{Style.RESET_ALL} {Fore.WHITE}npm install{Style.RESET_ALL}")
672
+ print(f" {Fore.GREEN}3.{Style.RESET_ALL} {Fore.WHITE}npm run dev{Style.RESET_ALL}")
673
+ print(f" {Fore.GREEN}4.{Style.RESET_ALL} {Fore.WHITE}Visit http://localhost:3000{Style.RESET_ALL}")
674
+ elif technology == "react":
675
+ print(f" {Fore.GREEN}1.{Style.RESET_ALL} {Fore.WHITE}cd {project_name}{Style.RESET_ALL}")
676
+ print(f" {Fore.GREEN}2.{Style.RESET_ALL} {Fore.WHITE}npm install{Style.RESET_ALL}")
677
+ print(f" {Fore.GREEN}3.{Style.RESET_ALL} {Fore.WHITE}npm run dev{Style.RESET_ALL}")
678
+ print(f" {Fore.GREEN}4.{Style.RESET_ALL} {Fore.WHITE}Visit http://localhost:5173{Style.RESET_ALL}")
679
+ elif technology == "react-admin":
680
+ print(f" {Fore.GREEN}1.{Style.RESET_ALL} {Fore.WHITE}cd {project_name}{Style.RESET_ALL}")
681
+ print(f" {Fore.GREEN}2.{Style.RESET_ALL} {Fore.WHITE}npm install{Style.RESET_ALL}")
682
+ print(f" {Fore.GREEN}3.{Style.RESET_ALL} {Fore.WHITE}npm run dev{Style.RESET_ALL}")
683
+ print(f" {Fore.GREEN}4.{Style.RESET_ALL} {Fore.WHITE}Visit http://localhost:5173{Style.RESET_ALL}")
684
+ elif technology == "flutter":
685
+ print(f" {Fore.GREEN}1.{Style.RESET_ALL} {Fore.WHITE}cd {project_name}{Style.RESET_ALL}")
686
+ print(f" {Fore.GREEN}2.{Style.RESET_ALL} {Fore.WHITE}flutter pub get{Style.RESET_ALL}")
687
+ print(f" {Fore.GREEN}3.{Style.RESET_ALL} {Fore.WHITE}flutter run{Style.RESET_ALL}")
688
+ print(f" {Fore.GREEN}4.{Style.RESET_ALL} {Fore.WHITE}App will run on connected device/emulator{Style.RESET_ALL}")
689
+
690
+ # Additional resources
691
+ print(f"\n{Fore.BLUE}📚 Resources:{Style.RESET_ALL}")
692
+ print(f" {Fore.WHITE}• Check the README.md for detailed setup instructions{Style.RESET_ALL}")
693
+ print(f" {Fore.WHITE}• Explore the .knowledge/ directory for AI documentation{Style.RESET_ALL}")
694
+ print(f" {Fore.WHITE}• Use 'ntc --help' for more commands{Style.RESET_ALL}")
695
+
696
+ print(f"\n{Fore.YELLOW}Happy coding! 🚀{Style.RESET_ALL}")
697
+
698
+ # Wait for user acknowledgment
699
+ print(f"\n{Fore.CYAN}Press any key to exit...{Style.RESET_ALL}")
700
+ get_key()
701
+
702
+ def main():
703
+ parser = argparse.ArgumentParser(
704
+ description="NTC - Nexent Toolkit Console",
705
+ formatter_class=argparse.RawDescriptionHelpFormatter,
706
+ epilog="""
707
+ Examples:
708
+ ntc init # Interactive mode with all options
709
+ ntc init --technology django # Quick Django project
710
+ ntc init --technology react # Quick React project
711
+ ntc init --technology nextjs # Quick Next.js project
712
+ ntc init --technology flutter # Quick Flutter project
713
+ ntc init --frontend react # Choose React frontend, ask for backend
714
+ ntc compose myproject # Compose full-stack project with multiple components
715
+ ntc start # Start all services from ntc.yml configuration
716
+ ntc create app myapp # Create new Django app with NTC structure
717
+ ntc drf init path name # Legacy Django REST Framework initialization
718
+ """
719
+ )
720
+
721
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
722
+
723
+ # Enhanced init command
724
+ init_parser = subparsers.add_parser("init", help="Interactive project initialization")
725
+ init_parser.add_argument('--technology', '-t', type=str,
726
+ choices=['django', 'react', 'react-admin', 'nextjs', 'flutter'],
727
+ help='Technology to use (django, react, react-admin, nextjs, flutter)')
728
+ init_parser.add_argument("--backend",
729
+ choices=["django", "drf", "laravel"],
730
+ help="Backend technology")
731
+ init_parser.add_argument("--frontend",
732
+ choices=["react", "react-admin", "nextjs", "flutter"],
733
+ help="Frontend technology")
734
+
735
+ # Create command for apps
736
+ create_parser = subparsers.add_parser("create", help="Create new components")
737
+ create_subparsers = create_parser.add_subparsers(dest="create_type", help="Type of component to create")
738
+
739
+ # Create app subcommand
740
+ app_parser = create_subparsers.add_parser("app", help="Create new Django app with NTC structure")
741
+ app_parser.add_argument("app_name", help="Name of the app to create")
742
+
743
+ # Legacy DRF command for backward compatibility
744
+ drf_parser = subparsers.add_parser("drf", help="Django REST Framework commands (legacy)")
745
+ drf_subparsers = drf_parser.add_subparsers(dest="drf_action")
746
+ drf_init_parser = drf_subparsers.add_parser("init", help="Initialize DRF project")
747
+ drf_init_parser.add_argument("path", help="Base path to create the project")
748
+ drf_init_parser.add_argument("name", help="Project name")
749
+
750
+ # Composer command for full-stack project composition
751
+ composer_parser = subparsers.add_parser("compose", help="Compose a full-stack project with multiple components")
752
+ composer_parser.add_argument("project_name", help="Name of the project")
753
+ composer_parser.add_argument("--path", help="Base path to create the project (default: current directory)")
754
+
755
+ # Start services command
756
+ start_parser = subparsers.add_parser("start", help="Start all services defined in ntc.yml")
757
+ start_parser.add_argument("--path", help="Path to project root directory (default: current directory)")
758
+
759
+ args = parser.parse_args()
760
+
761
+ if args.command == "init":
762
+ # Determine project type and technology from arguments
763
+ project_type = None
764
+ technology = None
765
+ ask_for_other = False
766
+
767
+ if args.technology:
768
+ # Direct technology specified - skip both project type and technology selection
769
+ if args.technology in ["django", "drf", "laravel"]:
770
+ project_type = "backend"
771
+ technology = "django" if args.technology == "drf" else args.technology
772
+ else: # react, react-admin, next, vue
773
+ project_type = "frontend"
774
+ technology = args.technology
775
+ elif args.backend:
776
+ # Backend specified, but we still need to ask what kind of backend
777
+ project_type = "backend"
778
+ if args.backend == "drf":
779
+ technology = "django"
780
+ else:
781
+ technology = args.backend
782
+ elif args.frontend:
783
+ # Frontend specified, but we still need to ask what kind of frontend
784
+ project_type = "frontend"
785
+ technology = args.frontend
786
+
787
+ # Call enhanced interactive init with pre-selected options
788
+ interactive_init(preset_project_type=project_type, preset_technology=technology)
789
+ elif args.command == "create" and args.create_type == "app":
790
+ create_app_structure(args.app_name)
791
+ elif args.command == "drf" and args.drf_action == "init":
792
+ # Legacy support
793
+ init_drf_project(args.path, args.name)
794
+ elif args.command == "compose":
795
+ # Composer for full-stack project composition
796
+ if args.path:
797
+ compose_project(args.project_name, args.path)
798
+ else:
799
+ compose_project(args.project_name)
800
+ elif args.command == "start":
801
+ # Start services from ntc.yml configuration
802
+ if args.path:
803
+ start_services(args.path)
804
+ else:
805
+ start_services()
806
+ else:
807
+ # Show help if no command provided
808
+ print_banner()
809
+ print(f"{Fore.CYAN}💡 Quick Start:{Style.RESET_ALL}")
810
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc init'{Style.RESET_ALL} {Fore.WHITE}for interactive setup{Style.RESET_ALL}")
811
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc init django'{Style.RESET_ALL} {Fore.WHITE}for Django project{Style.RESET_ALL}")
812
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc init react-admin'{Style.RESET_ALL} {Fore.WHITE}for React Admin Dashboard{Style.RESET_ALL}")
813
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc compose myproject'{Style.RESET_ALL} {Fore.WHITE}for full-stack composition{Style.RESET_ALL}")
814
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc start'{Style.RESET_ALL} {Fore.WHITE}to start all services{Style.RESET_ALL}")
815
+ print(f" {Fore.WHITE}• Run {Fore.GREEN}'ntc create app <name>'{Style.RESET_ALL} {Fore.WHITE}to add Django apps{Style.RESET_ALL}")
816
+ print()
817
+ parser.print_help()
818
+
819
+ if __name__ == "__main__":
820
+ main()