|
1 | 1 | <?php |
2 | | -namespace app\commands; |
3 | 2 |
|
4 | | -use Ahc\Cli\Input\Option; |
5 | | -use Ahc\Cli\Output\Writer; |
6 | | -use Ahc\Cli\IO\Interactor; |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace flight\commands; |
| 6 | + |
7 | 7 | use Ahc\Cli\Input\Command; |
8 | 8 |
|
| 9 | +/** |
| 10 | + * @property-read ?string $gitignoreFile |
| 11 | + * @property-read ?string $credsFile |
| 12 | + */ |
9 | 13 | class AiInitCommand extends Command |
10 | 14 | { |
| 15 | + /** |
| 16 | + * Constructor for the AiInitCommand class. |
| 17 | + * |
| 18 | + * Initializes the command instance and sets up any required dependencies. |
| 19 | + */ |
11 | 20 | public function __construct() |
12 | 21 | { |
13 | 22 | parent::__construct('ai:init', 'Initialize LLM API credentials and settings'); |
| 23 | + $this |
| 24 | + ->option('--gitignore-file', 'Path to .gitignore file', null, '') |
| 25 | + ->option('--creds-file', 'Path to .runway-creds.json file', null, ''); |
14 | 26 | } |
15 | 27 |
|
16 | 28 | /** |
17 | 29 | * Executes the function |
18 | 30 | * |
19 | | - * @return void |
| 31 | + * @return int |
20 | 32 | */ |
21 | 33 | public function execute() |
22 | 34 | { |
23 | | - $io = $this->app()->io(); |
| 35 | + $io = $this->app()->io(); |
24 | 36 |
|
25 | 37 | $io->info('Welcome to AI Init!', true); |
26 | 38 |
|
27 | | - // if runway creds already exist, prompt to overwrite |
28 | | - $baseDir = getcwd() . DIRECTORY_SEPARATOR; |
29 | | - $runwayCredsFile = $baseDir . '.runway-creds.json'; |
30 | | - |
31 | | - // make sure the .runway-creds.json file is not already present |
32 | | - if (file_exists($runwayCredsFile)) { |
33 | | - $io->error('.runway-creds.json file already exists. Please remove it before running this command.', true); |
34 | | - // prompt to overwrite |
35 | | - $overwrite = $io->confirm('Do you want to overwrite the existing .runway-creds.json file?', 'n'); |
36 | | - if ($overwrite === false) { |
37 | | - $io->info('Exiting without changes.', true); |
38 | | - return 0; |
39 | | - } |
40 | | - } |
41 | | - |
42 | | - // Prompt for API provider with validation |
43 | | - do { |
44 | | - $api = $io->prompt('Which LLM API do you want to use? (openai, grok, claude) [openai]', 'openai'); |
45 | | - $api = strtolower(trim($api)); |
46 | | - if (!in_array($api, ['openai', 'grok', 'claude'], true)) { |
47 | | - $io->error('Invalid API provider. Please enter one of: openai, grok, claude.', true); |
48 | | - $api = ''; |
49 | | - } |
50 | | - } while (empty($api)); |
51 | | - |
52 | | - // Prompt for base URL with validation |
53 | | - do { |
54 | | - switch($api) { |
55 | | - case 'openai': |
56 | | - $defaultBaseUrl = 'https://api.openai.com'; |
57 | | - break; |
58 | | - case 'grok': |
59 | | - $defaultBaseUrl = 'https://api.x.ai'; |
60 | | - break; |
61 | | - case 'claude': |
62 | | - $defaultBaseUrl = 'https://api.anthropic.com'; |
63 | | - break; |
64 | | - default: |
65 | | - $defaultBaseUrl = ''; |
66 | | - } |
67 | | - $baseUrl = $io->prompt('Enter the base URL for the LLM API', $defaultBaseUrl); |
68 | | - $baseUrl = trim($baseUrl); |
69 | | - if (empty($baseUrl) || !filter_var($baseUrl, FILTER_VALIDATE_URL)) { |
70 | | - $io->error('Base URL cannot be empty and must be a valid URL.', true); |
71 | | - $baseUrl = ''; |
72 | | - } |
73 | | - } while (empty($baseUrl)); |
| 39 | + $baseDir = getcwd() . DIRECTORY_SEPARATOR; |
| 40 | + $runwayCredsFile = $this->credsFile ?: $baseDir . '.runway-creds.json'; |
| 41 | + $gitignoreFile = $this->gitignoreFile ?: $baseDir . '.gitignore'; |
74 | 42 |
|
75 | | - // Validate API key input |
76 | | - do { |
77 | | - $apiKey = $io->prompt('Enter your API key for ' . $api); |
78 | | - if (empty(trim($apiKey))) { |
79 | | - $io->error('API key cannot be empty. Please enter a valid API key.', true); |
| 43 | + // make sure the .runway-creds.json file is not already present |
| 44 | + if (file_exists($runwayCredsFile)) { |
| 45 | + $io->error('.runway-creds.json file already exists. Please remove it before running this command.', true); |
| 46 | + // prompt to overwrite |
| 47 | + $overwrite = $io->confirm('Do you want to overwrite the existing .runway-creds.json file?', 'n'); |
| 48 | + if ($overwrite === false) { |
| 49 | + $io->info('Exiting without changes.', true); |
| 50 | + return 0; |
80 | 51 | } |
81 | | - } while (empty(trim($apiKey))); |
| 52 | + } |
| 53 | + |
| 54 | + // Prompt for API provider with validation |
| 55 | + $allowedApis = [ |
| 56 | + '1' => 'openai', |
| 57 | + '2' => 'grok', |
| 58 | + '3' => 'claude' |
| 59 | + ]; |
| 60 | + $apiChoice = strtolower(trim($io->choice('Which LLM API do you want to use?', $allowedApis, '1'))); |
| 61 | + $api = $allowedApis[$apiChoice] ?? 'openai'; |
| 62 | + |
| 63 | + // Prompt for base URL with validation |
| 64 | + switch ($api) { |
| 65 | + case 'openai': |
| 66 | + $defaultBaseUrl = 'https://api.openai.com'; |
| 67 | + break; |
| 68 | + case 'grok': |
| 69 | + $defaultBaseUrl = 'https://api.x.ai'; |
| 70 | + break; |
| 71 | + case 'claude': |
| 72 | + $defaultBaseUrl = 'https://api.anthropic.com'; |
| 73 | + break; |
| 74 | + } |
| 75 | + $baseUrl = trim($io->prompt('Enter the base URL for the LLM API', $defaultBaseUrl)); |
| 76 | + if (empty($baseUrl) || !filter_var($baseUrl, FILTER_VALIDATE_URL)) { |
| 77 | + $io->error('Base URL cannot be empty and must be a valid URL.', true); |
| 78 | + return 1; |
| 79 | + } |
| 80 | + |
| 81 | + // Validate API key input |
| 82 | + $apiKey = trim($io->prompt('Enter your API key for ' . $api)); |
| 83 | + if (empty($apiKey)) { |
| 84 | + $io->error('API key cannot be empty. Please enter a valid API key.', true); |
| 85 | + return 1; |
| 86 | + } |
82 | 87 |
|
83 | 88 | // Validate model input |
84 | | - do { |
85 | | - switch($api) { |
86 | | - case 'openai': |
87 | | - $defaultModel = 'gpt-4o'; |
88 | | - break; |
89 | | - case 'grok': |
90 | | - $defaultModel = 'grok-3-beta'; |
91 | | - break; |
92 | | - case 'claude': |
93 | | - $defaultModel = 'claude-3-opus'; |
94 | | - break; |
95 | | - default: |
96 | | - $defaultModel = ''; |
97 | | - } |
98 | | - $model = $io->prompt('Enter the model name you want to use (e.g. gpt-4, claude-3-opus, etc)', $defaultModel); |
99 | | - if (empty(trim($model))) { |
100 | | - $io->error('Model name cannot be empty. Please enter a valid model name.', true); |
101 | | - } |
102 | | - } while (empty(trim($model))); |
| 89 | + switch ($api) { |
| 90 | + case 'openai': |
| 91 | + $defaultModel = 'gpt-4o'; |
| 92 | + break; |
| 93 | + case 'grok': |
| 94 | + $defaultModel = 'grok-3-beta'; |
| 95 | + break; |
| 96 | + case 'claude': |
| 97 | + $defaultModel = 'claude-3-opus'; |
| 98 | + break; |
| 99 | + } |
| 100 | + $model = trim($io->prompt('Enter the model name you want to use (e.g. gpt-4, claude-3-opus, etc)', $defaultModel)); |
103 | 101 |
|
104 | 102 | $creds = [ |
105 | 103 | 'provider' => $api, |
106 | 104 | 'api_key' => $apiKey, |
107 | 105 | 'model' => $model, |
108 | | - 'base_url' => $baseUrl, |
| 106 | + 'base_url' => $baseUrl, |
109 | 107 | ]; |
110 | 108 |
|
111 | 109 | $json = json_encode($creds, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); |
112 | 110 | $file = $runwayCredsFile; |
113 | | - if (file_put_contents($file, $json) === false) { |
114 | | - $io->error('Failed to write credentials to ' . $file, true); |
115 | | - return 1; |
116 | | - } |
| 111 | + file_put_contents($file, $json); |
| 112 | + |
| 113 | + // change permissions to 600 |
| 114 | + chmod($file, 0600); |
| 115 | + |
117 | 116 | $io->ok('Credentials saved to ' . $file, true); |
118 | 117 |
|
119 | | - // run a check to make sure that the creds file is in the .gitignore file |
120 | | - $gitignoreFile = $baseDir . '.gitignore'; |
121 | | - if (!file_exists($gitignoreFile)) { |
122 | | - // create the .gitignore file if it doesn't exist |
123 | | - file_put_contents($gitignoreFile, ".runway-creds.json\n"); |
124 | | - $io->info('.gitignore file created and .runway-creds.json added to it.', true); |
125 | | - } else { |
126 | | - // check if the .runway-creds.json file is already in the .gitignore file |
127 | | - $gitignoreContents = file_get_contents($gitignoreFile); |
128 | | - if (strpos($gitignoreContents, '.runway-creds.json') === false) { |
129 | | - // add the .runway-creds.json file to the .gitignore file |
130 | | - file_put_contents($gitignoreFile, "\n.runway-creds.json\n", FILE_APPEND); |
131 | | - $io->info('.runway-creds.json added to .gitignore file.', true); |
132 | | - } else { |
133 | | - $io->info('.runway-creds.json is already in the .gitignore file.', true); |
134 | | - } |
135 | | - } |
| 118 | + // run a check to make sure that the creds file is in the .gitignore file |
| 119 | + // use $gitignoreFile instead of hardcoded path |
| 120 | + if (!file_exists($gitignoreFile)) { |
| 121 | + // create the .gitignore file if it doesn't exist |
| 122 | + file_put_contents($gitignoreFile, basename($runwayCredsFile) . "\n"); |
| 123 | + $io->info(basename($gitignoreFile) . ' file created and ' . basename($runwayCredsFile) . ' added to it.', true); |
| 124 | + } else { |
| 125 | + // check if the creds file is already in the .gitignore file |
| 126 | + $gitignoreContents = file_get_contents($gitignoreFile); |
| 127 | + if (strpos($gitignoreContents, basename($runwayCredsFile)) === false) { |
| 128 | + // add the creds file to the .gitignore file |
| 129 | + file_put_contents($gitignoreFile, "\n" . basename($runwayCredsFile) . "\n", FILE_APPEND); |
| 130 | + $io->info(basename($runwayCredsFile) . ' added to ' . basename($gitignoreFile) . ' file.', true); |
| 131 | + } else { |
| 132 | + $io->info(basename($runwayCredsFile) . ' is already in the ' . basename($gitignoreFile) . ' file.', true); |
| 133 | + } |
| 134 | + } |
136 | 135 |
|
137 | 136 | return 0; |
138 | 137 | } |
|
0 commit comments