88use OpenForgeProject \MageForge \Console \Command \AbstractCommand ;
99use OpenForgeProject \MageForge \Model \ThemeList ;
1010use OpenForgeProject \MageForge \Model \ThemePath ;
11+ use OpenForgeProject \MageForge \Service \EnvironmentService ;
12+ use OpenForgeProject \MageForge \Service \HyvaTokens \ConfigReader ;
1113use OpenForgeProject \MageForge \Service \HyvaTokens \TokenProcessor ;
1214use OpenForgeProject \MageForge \Service \ThemeBuilder \HyvaThemes \Builder as HyvaBuilder ;
1315use Symfony \Component \Console \Command \Command ;
@@ -25,12 +27,16 @@ class TokensCommand extends AbstractCommand
2527 * @param ThemeList $themeList
2628 * @param TokenProcessor $tokenProcessor
2729 * @param HyvaBuilder $hyvaBuilder
30+ * @param ConfigReader $configReader
31+ * @param EnvironmentService $environmentService
2832 */
2933 public function __construct (
3034 private readonly ThemePath $ themePath ,
3135 private readonly ThemeList $ themeList ,
3236 private readonly TokenProcessor $ tokenProcessor ,
33- private readonly HyvaBuilder $ hyvaBuilder
37+ private readonly HyvaBuilder $ hyvaBuilder ,
38+ private readonly ConfigReader $ configReader ,
39+ private readonly EnvironmentService $ environmentService ,
3440 ) {
3541 parent ::__construct ();
3642 }
@@ -90,7 +96,7 @@ private function selectThemeInteractively(OutputInterface $output): ?string
9096 }
9197
9298 // Check if we're in an interactive terminal environment
93- if (!$ this ->isInteractiveTerminal ($ output )) {
99+ if (!$ this ->environmentService -> isInteractiveTerminal ()) {
94100 $ this ->displayAvailableThemes ($ hyvaThemes );
95101 return null ;
96102 }
@@ -127,19 +133,28 @@ private function promptForTheme(array $hyvaThemes): ?string
127133 $ options [] = $ theme ->getCode ();
128134 }
129135
136+ // Set environment variables for Laravel Prompts
137+ $ this ->environmentService ->setPromptEnvironment ();
138+
130139 $ themeCodePrompt = new SelectPrompt (
131140 label: 'Select Hyvä theme to generate tokens for ' ,
132141 options: $ options ,
133142 hint: 'Arrow keys to navigate, Enter to confirm '
134143 );
135144
136145 try {
137- return $ themeCodePrompt ->prompt ();
146+ $ selectedTheme = $ themeCodePrompt ->prompt ();
147+ \Laravel \Prompts \Prompt::terminal ()->restoreTty ();
148+
149+ // Reset environment
150+ $ this ->environmentService ->resetPromptEnvironment ();
151+
152+ return $ selectedTheme ;
138153 } catch (\Exception $ e ) {
154+ // Reset environment on exception
155+ $ this ->environmentService ->resetPromptEnvironment ();
139156 $ this ->io ->error ('Interactive mode failed: ' . $ e ->getMessage ());
140157 return null ;
141- } finally {
142- \Laravel \Prompts \Prompt::terminal ()->restoreTty ();
143158 }
144159 }
145160
@@ -176,11 +191,23 @@ private function validateTheme(string $themeCode): ?string
176191 */
177192 private function processTokens (string $ themeCode , string $ themePath ): int
178193 {
194+ // Check if this is a vendor theme and inform user
195+ if ($ this ->configReader ->isVendorTheme ($ themePath )) {
196+ $ this ->io ->warning ([
197+ 'This is a vendor theme. The generated CSS will be stored in: ' ,
198+ 'var/view_preprocessed/hyva-tokens/[vendor]/[theme]/ ' ,
199+ '' ,
200+ '⚠️ Important: This location is temporary and may be cleared by cache operations. ' ,
201+ 'Consider copying the tokens.css to your custom theme or project. ' ,
202+ ]);
203+ $ this ->io ->newLine ();
204+ }
205+
179206 $ this ->io ->text ("Processing design tokens for theme: <fg=cyan> $ themeCode</> " );
180207 $ result = $ this ->tokenProcessor ->process ($ themePath );
181208
182209 if ($ result ['success ' ]) {
183- return $ this ->handleSuccess ($ result );
210+ return $ this ->handleSuccess ($ result, $ themePath );
184211 }
185212
186213 return $ this ->handleFailure ($ result );
@@ -190,15 +217,27 @@ private function processTokens(string $themeCode, string $themePath): int
190217 * Handle successful token processing
191218 *
192219 * @param array $result
220+ * @param string $themePath
193221 * @return int
194222 */
195- private function handleSuccess (array $ result ): int
223+ private function handleSuccess (array $ result, string $ themePath ): int
196224 {
197225 $ this ->io ->newLine ();
198226 $ this ->io ->success ($ result ['message ' ]);
199227 $ this ->io ->writeln ("Output file: <fg=green> {$ result ['outputPath ' ]}</> " );
200228 $ this ->io ->newLine ();
201229 $ this ->io ->text ('ℹ️ Make sure to import this file in your Tailwind CSS configuration. ' );
230+
231+ if ($ this ->configReader ->isVendorTheme ($ themePath )) {
232+ $ this ->io ->newLine ();
233+ $ this ->io ->note ([
234+ 'Since this is a vendor theme, consider one of these options: ' ,
235+ '1. Copy the generated CSS to your custom theme ' ,
236+ '2. Reference it in your Tailwind config with an absolute path ' ,
237+ '3. Add it to your build process to regenerate after cache:clean ' ,
238+ ]);
239+ }
240+
202241 return Command::SUCCESS ;
203242 }
204243
@@ -257,27 +296,4 @@ private function getHyvaThemes(): array
257296
258297 return $ hyvaThemes ;
259298 }
260-
261- /**
262- * Check if the current environment supports interactive terminal input
263- *
264- * @param OutputInterface $output
265- * @return bool
266- */
267- private function isInteractiveTerminal (OutputInterface $ output ): bool
268- {
269- // Check if output is decorated (supports ANSI codes)
270- if (!$ output ->isDecorated ()) {
271- return false ;
272- }
273-
274- // Check if STDIN is available and readable
275- if (!defined ('STDIN ' ) || !is_resource (STDIN )) {
276- return false ;
277- }
278-
279- // Additional check: try to detect if running in a proper TTY
280- $ sttyOutput = shell_exec ('stty -g 2>/dev/null ' );
281- return !empty ($ sttyOutput );
282- }
283299}
0 commit comments