gitarsenal-cli 1.9.106 → 1.9.108

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.
@@ -138,21 +138,37 @@ async function createVirtualEnvironment() {
138
138
 
139
139
  console.log(chalk.gray(`šŸ”„ Installing packages in virtual environment with uv...`));
140
140
 
141
+ // Determine the activation command based on platform
142
+ const isWindows = process.platform === 'win32';
143
+ const activateCmd = isWindows ?
144
+ 'call .venv\\Scripts\\activate.bat && ' :
145
+ 'source .venv/bin/activate && ';
146
+
141
147
  // Install packages using uv pip from requirements.txt
142
148
  const requirementsPath = path.join(packageDir, 'python', 'requirements.txt');
143
149
  if (await fs.pathExists(requirementsPath)) {
144
150
  console.log(chalk.gray(`šŸ“¦ Installing packages from requirements.txt...`));
145
- await execAsync(`uv pip install -r ${requirementsPath}`, {
151
+ const installCmd = isWindows ?
152
+ `${activateCmd}uv pip install -r ${requirementsPath}` :
153
+ `bash -c "${activateCmd}uv pip install -r ${requirementsPath}"`;
154
+
155
+ await execAsync(installCmd, {
146
156
  cwd: packageDir,
147
157
  env: { ...process.env, PYTHONIOENCODING: 'utf-8' },
148
- stdio: 'inherit'
158
+ stdio: 'inherit',
159
+ shell: isWindows ? 'cmd.exe' : '/bin/bash'
149
160
  });
150
161
  } else {
151
162
  console.log(chalk.gray(`šŸ“¦ Installing packages: ${packages.join(', ')}`));
152
- await execAsync(`uv pip install ${packages.join(' ')}`, {
163
+ const installCmd = isWindows ?
164
+ `${activateCmd}uv pip install ${packages.join(' ')}` :
165
+ `bash -c "${activateCmd}uv pip install ${packages.join(' ')}"`;
166
+
167
+ await execAsync(installCmd, {
153
168
  cwd: packageDir,
154
169
  env: { ...process.env, PYTHONIOENCODING: 'utf-8' },
155
- stdio: 'inherit'
170
+ stdio: 'inherit',
171
+ shell: isWindows ? 'cmd.exe' : '/bin/bash'
156
172
  });
157
173
  }
158
174
 
@@ -160,7 +176,7 @@ async function createVirtualEnvironment() {
160
176
 
161
177
  // Verify packages are installed
162
178
  const pythonPath = path.join(venvPath, 'bin', 'python');
163
- const packagesToVerify = [...packages, 'anthropic']; // Ensure anthropic is checked
179
+ const packagesToVerify = [...packages, 'anthropic', 'e2b_code_interpreter']; // Ensure anthropic and e2b are checked
164
180
  for (const pkg of packagesToVerify) {
165
181
  try {
166
182
  await execAsync(`${pythonPath} -c "import ${pkg}; print('${pkg} imported successfully')"`);
@@ -171,8 +187,6 @@ async function createVirtualEnvironment() {
171
187
  }
172
188
 
173
189
  // Create a script to activate the virtual environment
174
- const isWindows = process.platform === 'win32';
175
-
176
190
  const activateScript = isWindows ?
177
191
  `@echo off
178
192
  cd /d "%~dp0"
@@ -391,6 +405,7 @@ if __name__ == "__main__":
391
405
  • GitArsenal CLI (npm package)
392
406
  • Virtual environment with Python packages:
393
407
  - Modal
408
+ - E2B Code Interpreter
394
409
  - GitIngest
395
410
  - Requests
396
411
  - Anthropic (for Claude fallback)
package/tui/App.jsx ADDED
@@ -0,0 +1,326 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text, TextInput, List, Spinner } from '@opentui/react';
3
+
4
+ // Main TUI Application Component
5
+ export function App({ onSubmit, onExit }) {
6
+ const [screen, setScreen] = useState('menu');
7
+ const [repoUrl, setRepoUrl] = useState('');
8
+ const [selectedGpu, setSelectedGpu] = useState('A10G');
9
+ const [gpuCount, setGpuCount] = useState(1);
10
+ const [sandboxProvider, setSandboxProvider] = useState('modal');
11
+ const [isLoading, setIsLoading] = useState(false);
12
+ const [loadingText, setLoadingText] = useState('');
13
+ const [analysisData, setAnalysisData] = useState(null);
14
+
15
+ const gpuOptions = [
16
+ { label: 'T4 (16GB VRAM)', value: 'T4' },
17
+ { label: 'L4 (24GB VRAM)', value: 'L4' },
18
+ { label: 'A10G (24GB VRAM)', value: 'A10G' },
19
+ { label: 'A100-40 (40GB VRAM)', value: 'A100-40GB' },
20
+ { label: 'A100-80 (80GB VRAM)', value: 'A100-80GB' },
21
+ { label: 'L40S (48GB VRAM)', value: 'L40S' },
22
+ { label: 'H100 (80GB VRAM)', value: 'H100' },
23
+ { label: 'H200 (141GB VRAM)', value: 'H200' },
24
+ { label: 'B200 (141GB VRAM)', value: 'B200' }
25
+ ];
26
+
27
+ const gpuCountOptions = [
28
+ { label: '1 GPU', value: 1 },
29
+ { label: '2 GPUs', value: 2 },
30
+ { label: '3 GPUs', value: 3 },
31
+ { label: '4 GPUs', value: 4 },
32
+ { label: '6 GPUs', value: 6 },
33
+ { label: '8 GPUs', value: 8 }
34
+ ];
35
+
36
+ const menuItems = [
37
+ { label: 'šŸš€ Create New Sandbox', value: 'create' },
38
+ { label: 'šŸ“‹ Browse Repositories', value: 'browse' },
39
+ { label: 'šŸ”‘ API Keys Management', value: 'keys' },
40
+ { label: 'āš™ļø Settings', value: 'settings' },
41
+ { label: 'ā“ Help & Examples', value: 'help' },
42
+ { label: '🚪 Exit', value: 'exit' }
43
+ ];
44
+
45
+ const sandboxProviders = [
46
+ { label: 'Modal (GPU support, persistent volumes)', value: 'modal' },
47
+ { label: 'E2B (Faster startup, no GPU)', value: 'e2b' }
48
+ ];
49
+
50
+ const handleMenuSelect = (item) => {
51
+ if (item.value === 'exit') {
52
+ onExit();
53
+ } else if (item.value === 'create') {
54
+ setScreen('repo-input');
55
+ } else if (item.value === 'keys') {
56
+ setScreen('keys');
57
+ } else if (item.value === 'help') {
58
+ setScreen('help');
59
+ } else if (item.value === 'settings') {
60
+ setScreen('settings');
61
+ }
62
+ };
63
+
64
+ const handleRepoSubmit = () => {
65
+ if (repoUrl.trim()) {
66
+ setScreen('provider-select');
67
+ }
68
+ };
69
+
70
+ const handleProviderSelect = (provider) => {
71
+ setSandboxProvider(provider.value);
72
+ if (provider.value === 'modal') {
73
+ setScreen('gpu-select');
74
+ } else {
75
+ // E2B doesn't need GPU selection
76
+ handleSubmit();
77
+ }
78
+ };
79
+
80
+ const handleGpuSelect = (gpu) => {
81
+ setSelectedGpu(gpu.value);
82
+ setScreen('gpu-count');
83
+ };
84
+
85
+ const handleGpuCountSelect = (count) => {
86
+ setGpuCount(count.value);
87
+ setScreen('confirm');
88
+ };
89
+
90
+ const handleSubmit = () => {
91
+ const config = {
92
+ repoUrl,
93
+ gpuType: selectedGpu,
94
+ gpuCount,
95
+ sandboxProvider,
96
+ analysisData
97
+ };
98
+ onSubmit(config);
99
+ };
100
+
101
+ // Render different screens
102
+ if (isLoading) {
103
+ return (
104
+ <Box flexDirection="column" padding={2} gap={1}>
105
+ <Box borderStyle="round" borderColor="blue" padding={1}>
106
+ <Text bold color="cyan">ā³ GitArsenal</Text>
107
+ </Box>
108
+ <Box flexDirection="row" gap={1} marginTop={1}>
109
+ <Spinner />
110
+ <Text>{loadingText}</Text>
111
+ </Box>
112
+ </Box>
113
+ );
114
+ }
115
+
116
+ if (screen === 'menu') {
117
+ return (
118
+ <Box flexDirection="column" padding={2} gap={1}>
119
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
120
+ <Text bold color="cyan">šŸŽÆ GitArsenal - GPU-Accelerated Repository Sandbox</Text>
121
+ </Box>
122
+ <Box marginTop={1}>
123
+ <Text color="gray">Secure, cloud-based development environments with GPU acceleration</Text>
124
+ </Box>
125
+ <Box marginTop={1}>
126
+ <List
127
+ items={menuItems}
128
+ onSelect={handleMenuSelect}
129
+ selectedStyle={{ color: 'cyan', bold: true }}
130
+ />
131
+ </Box>
132
+ <Box marginTop={1}>
133
+ <Text color="gray" dim>Use ↑↓ arrows to navigate, Enter to select, Ctrl+C to exit</Text>
134
+ </Box>
135
+ </Box>
136
+ );
137
+ }
138
+
139
+ if (screen === 'repo-input') {
140
+ return (
141
+ <Box flexDirection="column" padding={2} gap={1}>
142
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
143
+ <Text bold color="cyan">šŸš€ Create New Sandbox</Text>
144
+ </Box>
145
+ <Box marginTop={1}>
146
+ <Text>Enter GitHub repository URL:</Text>
147
+ </Box>
148
+ <Box marginTop={1}>
149
+ <TextInput
150
+ value={repoUrl}
151
+ onChange={setRepoUrl}
152
+ onSubmit={handleRepoSubmit}
153
+ placeholder="https://github.com/username/repository.git"
154
+ />
155
+ </Box>
156
+ <Box marginTop={1}>
157
+ <Text color="gray" dim>Examples:</Text>
158
+ <Text color="gray" dim>• https://github.com/microsoft/transformer</Text>
159
+ <Text color="gray" dim>• https://github.com/pytorch/pytorch</Text>
160
+ <Text color="gray" dim>• https://github.com/openai/gpt-2</Text>
161
+ </Box>
162
+ <Box marginTop={1}>
163
+ <Text color="gray" dim>Press Enter to continue • Esc to go back</Text>
164
+ </Box>
165
+ </Box>
166
+ );
167
+ }
168
+
169
+ if (screen === 'provider-select') {
170
+ return (
171
+ <Box flexDirection="column" padding={2} gap={1}>
172
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
173
+ <Text bold color="cyan">šŸ”§ Select Sandbox Provider</Text>
174
+ </Box>
175
+ <Box marginTop={1}>
176
+ <Text>Repository: <Text color="green">{repoUrl}</Text></Text>
177
+ </Box>
178
+ <Box marginTop={1}>
179
+ <List
180
+ items={sandboxProviders}
181
+ onSelect={handleProviderSelect}
182
+ selectedStyle={{ color: 'cyan', bold: true }}
183
+ />
184
+ </Box>
185
+ <Box marginTop={1}>
186
+ <Text color="gray" dim>Press Esc to go back</Text>
187
+ </Box>
188
+ </Box>
189
+ );
190
+ }
191
+
192
+ if (screen === 'gpu-select') {
193
+ return (
194
+ <Box flexDirection="column" padding={2} gap={1}>
195
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
196
+ <Text bold color="cyan">⚔ Select GPU Configuration</Text>
197
+ </Box>
198
+ <Box marginTop={1}>
199
+ <Text>Repository: <Text color="green">{repoUrl}</Text></Text>
200
+ <Text>Provider: <Text color="green">{sandboxProvider}</Text></Text>
201
+ </Box>
202
+ <Box marginTop={1}>
203
+ <List
204
+ items={gpuOptions}
205
+ onSelect={handleGpuSelect}
206
+ selectedStyle={{ color: 'cyan', bold: true }}
207
+ />
208
+ </Box>
209
+ <Box marginTop={1}>
210
+ <Text color="gray" dim>Press Esc to go back</Text>
211
+ </Box>
212
+ </Box>
213
+ );
214
+ }
215
+
216
+ if (screen === 'gpu-count') {
217
+ return (
218
+ <Box flexDirection="column" padding={2} gap={1}>
219
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
220
+ <Text bold color="cyan">⚔ Select GPU Count</Text>
221
+ </Box>
222
+ <Box marginTop={1}>
223
+ <Text>GPU Type: <Text color="green">{selectedGpu}</Text></Text>
224
+ </Box>
225
+ <Box marginTop={1}>
226
+ <List
227
+ items={gpuCountOptions}
228
+ onSelect={handleGpuCountSelect}
229
+ selectedStyle={{ color: 'cyan', bold: true }}
230
+ />
231
+ </Box>
232
+ <Box marginTop={1}>
233
+ <Text color="gray" dim>Press Esc to go back</Text>
234
+ </Box>
235
+ </Box>
236
+ );
237
+ }
238
+
239
+ if (screen === 'confirm') {
240
+ return (
241
+ <Box flexDirection="column" padding={2} gap={1}>
242
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
243
+ <Text bold color="cyan">šŸ“‹ Configuration Summary</Text>
244
+ </Box>
245
+ <Box flexDirection="column" marginTop={1} gap={0}>
246
+ <Text><Text color="gray">Repository URL:</Text> <Text color="white">{repoUrl}</Text></Text>
247
+ <Text><Text color="gray">Sandbox Provider:</Text> <Text color="white">{sandboxProvider}</Text></Text>
248
+ {sandboxProvider === 'modal' && (
249
+ <>
250
+ <Text><Text color="gray">GPU Type:</Text> <Text color="white">{gpuCount > 1 ? `${gpuCount}x ${selectedGpu}` : selectedGpu}</Text></Text>
251
+ </>
252
+ )}
253
+ </Box>
254
+ <Box marginTop={1}>
255
+ <Text color="green" bold>āœ… Press Enter to create sandbox</Text>
256
+ <Text color="gray" dim>Press Esc to go back to menu</Text>
257
+ </Box>
258
+ </Box>
259
+ );
260
+ }
261
+
262
+ if (screen === 'keys') {
263
+ return (
264
+ <Box flexDirection="column" padding={2} gap={1}>
265
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
266
+ <Text bold color="cyan">šŸ”‘ API Keys Management</Text>
267
+ </Box>
268
+ <Box marginTop={1}>
269
+ <Text color="yellow">Coming soon! Use 'gitarsenal keys' command for now.</Text>
270
+ </Box>
271
+ <Box marginTop={1}>
272
+ <Text color="gray" dim>Press Esc to go back</Text>
273
+ </Box>
274
+ </Box>
275
+ );
276
+ }
277
+
278
+ if (screen === 'help') {
279
+ return (
280
+ <Box flexDirection="column" padding={2} gap={1}>
281
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
282
+ <Text bold color="cyan">ā“ Help & Examples</Text>
283
+ </Box>
284
+ <Box flexDirection="column" marginTop={1}>
285
+ <Text bold color="green">Quick Start:</Text>
286
+ <Text>1. Select "Create New Sandbox"</Text>
287
+ <Text>2. Enter a GitHub repository URL</Text>
288
+ <Text>3. Choose your sandbox provider</Text>
289
+ <Text>4. Select GPU type and count (Modal only)</Text>
290
+ <Text>5. Confirm and create!</Text>
291
+
292
+ <Text bold color="green" marginTop={1}>Example Repositories:</Text>
293
+ <Text>• https://github.com/pytorch/examples</Text>
294
+ <Text>• https://github.com/huggingface/transformers</Text>
295
+ <Text>• https://github.com/openai/whisper</Text>
296
+ </Box>
297
+ <Box marginTop={1}>
298
+ <Text color="gray" dim>Press Esc to go back</Text>
299
+ </Box>
300
+ </Box>
301
+ );
302
+ }
303
+
304
+ if (screen === 'settings') {
305
+ return (
306
+ <Box flexDirection="column" padding={2} gap={1}>
307
+ <Box borderStyle="round" borderColor="cyan" padding={1}>
308
+ <Text bold color="cyan">āš™ļø Settings</Text>
309
+ </Box>
310
+ <Box marginTop={1}>
311
+ <Text color="yellow">Coming soon!</Text>
312
+ </Box>
313
+ <Box marginTop={1}>
314
+ <Text color="gray" dim>Press Esc to go back</Text>
315
+ </Box>
316
+ </Box>
317
+ );
318
+ }
319
+
320
+ return (
321
+ <Box flexDirection="column" padding={2}>
322
+ <Text>Unknown screen: {screen}</Text>
323
+ </Box>
324
+ );
325
+ }
326
+
package/tui/index.js ADDED
@@ -0,0 +1,37 @@
1
+ const { render } = require('@opentui/react');
2
+ const React = require('react');
3
+ const { App } = require('./App.jsx');
4
+
5
+ /**
6
+ * Launch the OpenTUI interface
7
+ * @param {Object} options - Configuration options
8
+ * @returns {Promise<Object>} - Selected configuration
9
+ */
10
+ async function launchTUI(options = {}) {
11
+ return new Promise((resolve, reject) => {
12
+ const handleSubmit = (config) => {
13
+ resolve(config);
14
+ };
15
+
16
+ const handleExit = () => {
17
+ resolve(null);
18
+ };
19
+
20
+ try {
21
+ render(
22
+ React.createElement(App, {
23
+ onSubmit: handleSubmit,
24
+ onExit: handleExit,
25
+ initialOptions: options
26
+ })
27
+ );
28
+ } catch (error) {
29
+ reject(error);
30
+ }
31
+ });
32
+ }
33
+
34
+ module.exports = {
35
+ launchTUI
36
+ };
37
+
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Simple test to verify OpenTUI is working
4
+ const { terminal } = require('@opentui/core');
5
+
6
+ async function testOpenTUI() {
7
+ try {
8
+ console.log('Testing OpenTUI installation...');
9
+
10
+ // Create a simple terminal instance
11
+ const term = terminal();
12
+
13
+ // Test basic output
14
+ term.writeln('šŸŽØ OpenTUI Test');
15
+ term.writeln('āœ… OpenTUI core is installed and working!');
16
+ term.writeln('');
17
+ term.writeln('This confirms that:');
18
+ term.writeln(' • @opentui/core is installed');
19
+ term.writeln(' • Terminal interface is accessible');
20
+ term.writeln(' • Ready to build the full TUI');
21
+ term.writeln('');
22
+ term.writeln('Press any key to exit...');
23
+
24
+ // Wait for key press
25
+ await term.waitForKeyPress();
26
+
27
+ console.log('\nāœ… Test complete!');
28
+ process.exit(0);
29
+ } catch (error) {
30
+ console.error('āŒ OpenTUI test failed:', error.message);
31
+ console.error('');
32
+ console.error('This might mean:');
33
+ console.error(' • OpenTUI is not installed correctly');
34
+ console.error(' • API has changed');
35
+ console.error(' • Need to adjust the implementation');
36
+ process.exit(1);
37
+ }
38
+ }
39
+
40
+ testOpenTUI();
41
+