imcp 0.0.3 → 0.0.5
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.
- package/README.md +5 -6
- package/dist/cli/commands/install.js +2 -0
- package/dist/cli/commands/list.js +1 -0
- package/dist/cli/index.js +1 -2
- package/dist/core/ConfigurationLoader.d.ts +32 -0
- package/dist/core/ConfigurationLoader.js +213 -0
- package/dist/core/ConfigurationProvider.d.ts +2 -3
- package/dist/core/ConfigurationProvider.js +13 -182
- package/dist/core/InstallationService.d.ts +8 -0
- package/dist/core/InstallationService.js +124 -96
- package/dist/core/RequirementService.d.ts +1 -1
- package/dist/core/RequirementService.js +5 -9
- package/dist/core/constants.js +14 -1
- package/dist/core/installers/BaseInstaller.d.ts +5 -4
- package/dist/core/installers/BaseInstaller.js +17 -28
- package/dist/core/installers/ClientInstaller.js +159 -39
- package/dist/core/installers/CommandInstaller.d.ts +1 -0
- package/dist/core/installers/CommandInstaller.js +3 -0
- package/dist/core/installers/GeneralInstaller.d.ts +1 -0
- package/dist/core/installers/GeneralInstaller.js +3 -0
- package/dist/core/installers/InstallerFactory.d.ts +9 -7
- package/dist/core/installers/InstallerFactory.js +10 -8
- package/dist/core/installers/NpmInstaller.d.ts +1 -0
- package/dist/core/installers/NpmInstaller.js +3 -0
- package/dist/core/installers/PipInstaller.d.ts +6 -3
- package/dist/core/installers/PipInstaller.js +21 -8
- package/dist/core/installers/RequirementInstaller.d.ts +4 -3
- package/dist/core/installers/clients/ClientInstaller.d.ts +23 -0
- package/dist/core/installers/clients/ClientInstaller.js +573 -0
- package/dist/core/installers/clients/ExtensionInstaller.d.ts +26 -0
- package/dist/core/installers/clients/ExtensionInstaller.js +149 -0
- package/dist/core/installers/index.d.ts +8 -6
- package/dist/core/installers/index.js +8 -6
- package/dist/core/installers/requirements/BaseInstaller.d.ts +59 -0
- package/dist/core/installers/requirements/BaseInstaller.js +168 -0
- package/dist/core/installers/requirements/CommandInstaller.d.ts +37 -0
- package/dist/core/installers/requirements/CommandInstaller.js +173 -0
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +33 -0
- package/dist/core/installers/requirements/GeneralInstaller.js +86 -0
- package/dist/core/installers/requirements/InstallerFactory.d.ts +54 -0
- package/dist/core/installers/requirements/InstallerFactory.js +97 -0
- package/dist/core/installers/requirements/NpmInstaller.d.ts +26 -0
- package/dist/core/installers/requirements/NpmInstaller.js +128 -0
- package/dist/core/installers/requirements/PipInstaller.d.ts +28 -0
- package/dist/core/installers/requirements/PipInstaller.js +128 -0
- package/{src/core/installers/RequirementInstaller.ts → dist/core/installers/requirements/RequirementInstaller.d.ts} +33 -38
- package/dist/core/installers/requirements/RequirementInstaller.js +3 -0
- package/dist/core/types.d.ts +4 -1
- package/dist/services/ServerService.js +1 -1
- package/dist/utils/clientUtils.d.ts +0 -6
- package/dist/utils/clientUtils.js +3 -2
- package/dist/utils/githubUtils.d.ts +11 -0
- package/dist/utils/githubUtils.js +88 -0
- package/dist/utils/osUtils.d.ts +17 -0
- package/dist/utils/osUtils.js +184 -0
- package/dist/web/public/css/modal.css +97 -3
- package/dist/web/public/index.html +21 -2
- package/dist/web/public/js/modal.js +177 -28
- package/dist/web/public/js/serverCategoryDetails.js +12 -10
- package/dist/web/public/js/serverCategoryList.js +20 -5
- package/dist/web/public/modal.html +27 -13
- package/dist/web/server.js +1 -1
- package/package.json +2 -1
- package/src/cli/commands/install.ts +4 -2
- package/src/cli/commands/list.ts +1 -0
- package/src/cli/index.ts +1 -1
- package/src/core/ConfigurationLoader.ts +251 -0
- package/src/core/ConfigurationProvider.ts +13 -195
- package/src/core/InstallationService.ts +140 -106
- package/src/core/RequirementService.ts +5 -10
- package/src/core/constants.ts +15 -1
- package/src/core/installers/{ClientInstaller.ts → clients/ClientInstaller.ts} +185 -46
- package/src/core/installers/clients/ExtensionInstaller.ts +162 -0
- package/src/core/installers/index.ts +9 -7
- package/src/core/installers/{BaseInstaller.ts → requirements/BaseInstaller.ts} +10 -118
- package/src/core/installers/{CommandInstaller.ts → requirements/CommandInstaller.ts} +7 -3
- package/src/core/installers/{GeneralInstaller.ts → requirements/GeneralInstaller.ts} +6 -2
- package/src/core/installers/{InstallerFactory.ts → requirements/InstallerFactory.ts} +11 -9
- package/src/core/installers/{NpmInstaller.ts → requirements/NpmInstaller.ts} +7 -4
- package/src/core/installers/{PipInstaller.ts → requirements/PipInstaller.ts} +26 -10
- package/src/core/installers/requirements/RequirementInstaller.ts +41 -0
- package/src/core/types.ts +4 -1
- package/src/services/ServerService.ts +1 -1
- package/src/utils/clientUtils.ts +4 -2
- package/src/utils/githubUtils.ts +103 -0
- package/src/utils/osUtils.ts +206 -15
- package/src/web/public/css/modal.css +97 -3
- package/src/web/public/index.html +21 -2
- package/src/web/public/js/modal.js +177 -28
- package/src/web/public/js/serverCategoryDetails.js +12 -10
- package/src/web/public/js/serverCategoryList.js +20 -5
- package/src/web/public/modal.html +27 -13
- package/src/web/server.ts +1 -1
package/src/utils/osUtils.ts
CHANGED
|
@@ -14,7 +14,7 @@ export function getOSType(): OSType {
|
|
|
14
14
|
action: 'get_os_type',
|
|
15
15
|
platform
|
|
16
16
|
});
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
switch (platform) {
|
|
19
19
|
case 'win32':
|
|
20
20
|
return OSType.Windows;
|
|
@@ -36,7 +36,7 @@ export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
|
36
36
|
tool,
|
|
37
37
|
osType
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
try {
|
|
41
41
|
switch (osType) {
|
|
42
42
|
case OSType.Windows:
|
|
@@ -48,7 +48,7 @@ export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
|
48
48
|
// Refresh PATH environment variable after installation
|
|
49
49
|
await refreshPathEnv();
|
|
50
50
|
break;
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
case OSType.MacOS:
|
|
53
53
|
if (tool === 'git') {
|
|
54
54
|
await execAsync('brew install git');
|
|
@@ -60,7 +60,7 @@ export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
|
60
60
|
await execAsync('source ~/.zshrc || source ~/.bash_profile || source ~/.bashrc || true');
|
|
61
61
|
}
|
|
62
62
|
break;
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
case OSType.Linux:
|
|
65
65
|
if (tool === 'git') {
|
|
66
66
|
await execAsync('sudo apt-get update && sudo apt-get install -y git');
|
|
@@ -70,14 +70,14 @@ export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
|
70
70
|
// Source bash profile to refresh PATH
|
|
71
71
|
await execAsync('source ~/.bashrc || source ~/.profile || true');
|
|
72
72
|
break;
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
default:
|
|
75
75
|
throw new Error(`Unsupported operating system for installing ${tool}`);
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
// Wait a moment for system to register the new binaries
|
|
79
79
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
Logger.debug({
|
|
82
82
|
action: 'install_cli_success',
|
|
83
83
|
tool,
|
|
@@ -98,6 +98,7 @@ export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
|
98
98
|
* This is necessary because when tools are installed using package managers,
|
|
99
99
|
* they update the system PATH but the current Node process doesn't see those changes.
|
|
100
100
|
*/
|
|
101
|
+
|
|
101
102
|
export async function refreshPathEnv(): Promise<void> {
|
|
102
103
|
const osType = getOSType();
|
|
103
104
|
Logger.debug({
|
|
@@ -115,7 +116,7 @@ export async function refreshPathEnv(): Promise<void> {
|
|
|
115
116
|
Logger.debug('Refreshed PATH from Windows registry');
|
|
116
117
|
}
|
|
117
118
|
break;
|
|
118
|
-
|
|
119
|
+
|
|
119
120
|
case OSType.MacOS:
|
|
120
121
|
case OSType.Linux:
|
|
121
122
|
// On Unix systems, typical installation locations if PATH isn't updated
|
|
@@ -129,7 +130,7 @@ export async function refreshPathEnv(): Promise<void> {
|
|
|
129
130
|
'/opt/homebrew/bin', // For M1 Macs
|
|
130
131
|
`${os.homedir()}/.local/bin`
|
|
131
132
|
];
|
|
132
|
-
|
|
133
|
+
|
|
133
134
|
// Ensure these paths are in process.env.PATH
|
|
134
135
|
if (process.env.PATH) {
|
|
135
136
|
const currentPaths = process.env.PATH.split(':');
|
|
@@ -157,7 +158,7 @@ export async function isToolInstalled(tool: 'gh' | 'git', retries = 3): Promise<
|
|
|
157
158
|
tool,
|
|
158
159
|
retries
|
|
159
160
|
});
|
|
160
|
-
|
|
161
|
+
|
|
161
162
|
// Try to execute tool command
|
|
162
163
|
try {
|
|
163
164
|
await execAsync(`${tool} --version`);
|
|
@@ -171,17 +172,17 @@ export async function isToolInstalled(tool: 'gh' | 'git', retries = 3): Promise<
|
|
|
171
172
|
// If we have retries left, refresh PATH and try again
|
|
172
173
|
if (retries > 0) {
|
|
173
174
|
Logger.debug(`${tool} not found, refreshing PATH and retrying...`);
|
|
174
|
-
|
|
175
|
+
|
|
175
176
|
// Refresh environment PATH variable
|
|
176
177
|
await refreshPathEnv();
|
|
177
|
-
|
|
178
|
+
|
|
178
179
|
// Wait a moment before retrying
|
|
179
180
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
180
|
-
|
|
181
|
+
|
|
181
182
|
// Recursive retry with decremented counter
|
|
182
183
|
return isToolInstalled(tool, retries - 1);
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
+
|
|
185
186
|
// No retries left, tool is not installed
|
|
186
187
|
Logger.debug({
|
|
187
188
|
action: 'check_tool_installed_success',
|
|
@@ -233,7 +234,7 @@ export async function openBrowser(url: string): Promise<void> {
|
|
|
233
234
|
default:
|
|
234
235
|
throw new Error(`Unsupported operating system for opening browser`);
|
|
235
236
|
}
|
|
236
|
-
|
|
237
|
+
|
|
237
238
|
Logger.debug({
|
|
238
239
|
action: 'open_browser_success',
|
|
239
240
|
url,
|
|
@@ -247,4 +248,194 @@ export async function openBrowser(url: string): Promise<void> {
|
|
|
247
248
|
});
|
|
248
249
|
// Don't throw the error - just log it and continue
|
|
249
250
|
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Gets the directory containing Python packages (site-packages) based on Python executable path.
|
|
255
|
+
* Handles different Python installations (system, venv, conda) across different OS platforms.
|
|
256
|
+
* @param pythonExecutablePath The full path to the Python executable
|
|
257
|
+
* @returns The site-packages directory path
|
|
258
|
+
*/
|
|
259
|
+
export function getPythonPackagePath(pythonExecutablePath: string): string {
|
|
260
|
+
Logger.debug({
|
|
261
|
+
action: 'get_python_package_path',
|
|
262
|
+
pythonExecutablePath
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const dir = path.dirname(pythonExecutablePath);
|
|
267
|
+
const isWindows = process.platform === 'win32';
|
|
268
|
+
|
|
269
|
+
// Handle common Python installation patterns
|
|
270
|
+
if (isWindows) {
|
|
271
|
+
// Windows: Check for Scripts directory (venv) or python.exe location
|
|
272
|
+
if (dir.endsWith('Scripts')) {
|
|
273
|
+
// Virtual environment structure on Windows: <venv>/Scripts/python.exe
|
|
274
|
+
const venvRoot = path.dirname(dir);
|
|
275
|
+
return path.join(venvRoot, 'Lib', 'site-packages');
|
|
276
|
+
} else if (dir.toLowerCase().includes('python')) {
|
|
277
|
+
// System Python or Conda on Windows
|
|
278
|
+
return path.join(dir, 'Lib', 'site-packages');
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// Unix systems (MacOS/Linux)
|
|
282
|
+
if (dir.endsWith('bin')) {
|
|
283
|
+
// Virtual environment structure on Unix: <venv>/bin/python
|
|
284
|
+
const venvRoot = path.dirname(dir);
|
|
285
|
+
// Try to find python version-specific site-packages
|
|
286
|
+
const libDir = path.join(venvRoot, 'lib');
|
|
287
|
+
if (fs.existsSync(libDir)) {
|
|
288
|
+
const pythonDirs = fs.readdirSync(libDir).filter(d => d.startsWith('python'));
|
|
289
|
+
if (pythonDirs.length > 0) {
|
|
290
|
+
// Use the first python directory found
|
|
291
|
+
return path.join(libDir, pythonDirs[0], 'site-packages');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Fallback to a generic lib/python3/site-packages if version-specific not found
|
|
295
|
+
return path.join(venvRoot, 'lib', 'python3', 'site-packages');
|
|
296
|
+
} else if (dir.toLowerCase().includes('python')) {
|
|
297
|
+
// System Python or Conda on Unix
|
|
298
|
+
const libDir = path.join(dir, 'lib');
|
|
299
|
+
if (fs.existsSync(libDir)) {
|
|
300
|
+
const pythonDirs = fs.readdirSync(libDir).filter(d => d.startsWith('python'));
|
|
301
|
+
if (pythonDirs.length > 0) {
|
|
302
|
+
// Use the first python directory found
|
|
303
|
+
return path.join(libDir, pythonDirs[0], 'site-packages');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Fallback to a generic lib/python3/site-packages
|
|
307
|
+
return path.join(dir, 'lib', 'python3', 'site-packages');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Default fallback: return the original directory
|
|
312
|
+
Logger.debug('No standard Python directory structure found, using original directory');
|
|
313
|
+
return dir;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
Logger.error('Error getting Python package path', {
|
|
316
|
+
pythonExecutablePath,
|
|
317
|
+
error
|
|
318
|
+
});
|
|
319
|
+
return path.dirname(pythonExecutablePath);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Finds the directory of the system's default Python installation.
|
|
325
|
+
* @returns The directory path or null if not found.
|
|
326
|
+
*/
|
|
327
|
+
export async function getSystemPythonPackageDirectory(): Promise<string | null> {
|
|
328
|
+
const command = process.platform === 'win32' ? 'where python' : 'which python';
|
|
329
|
+
|
|
330
|
+
Logger.debug({
|
|
331
|
+
action: 'get_system_python_package_directory',
|
|
332
|
+
command
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
const { stdout } = await execAsync(command);
|
|
337
|
+
// Use the first path found, trim whitespace
|
|
338
|
+
const pythonPath = stdout.split('\n')[0].trim();
|
|
339
|
+
if (pythonPath) {
|
|
340
|
+
const packagePath = getPythonPackagePath(pythonPath);
|
|
341
|
+
Logger.debug({
|
|
342
|
+
action: 'get_system_python_package_directory_success',
|
|
343
|
+
pythonPath,
|
|
344
|
+
packagePath
|
|
345
|
+
});
|
|
346
|
+
return packagePath;
|
|
347
|
+
}
|
|
348
|
+
Logger.debug('No Python executable found');
|
|
349
|
+
return null;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
Logger.debug(`Could not find system python using "${command}": ${error}`);
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Gets the path of the system's default browser.
|
|
358
|
+
* @returns The path to the default browser executable.
|
|
359
|
+
*/
|
|
360
|
+
export async function GetBrowserPath(): Promise<string> {
|
|
361
|
+
const osType = getOSType();
|
|
362
|
+
Logger.debug({
|
|
363
|
+
action: 'get_system_browser_path',
|
|
364
|
+
osType
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
switch (osType) {
|
|
369
|
+
case OSType.Windows: {
|
|
370
|
+
// Check for Edge first
|
|
371
|
+
const edgePaths = [
|
|
372
|
+
`${process.env['PROGRAMFILES(X86)']}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
373
|
+
`${process.env['PROGRAMFILES']}\\Microsoft\\Edge\\Application\\msedge.exe`
|
|
374
|
+
];
|
|
375
|
+
for (const path of edgePaths) {
|
|
376
|
+
if (fs.existsSync(path)) {
|
|
377
|
+
return path;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Then check for Chrome
|
|
382
|
+
const chromePaths = [
|
|
383
|
+
`${process.env['PROGRAMFILES(X86)']}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
384
|
+
`${process.env['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe`
|
|
385
|
+
];
|
|
386
|
+
for (const path of chromePaths) {
|
|
387
|
+
if (fs.existsSync(path)) {
|
|
388
|
+
return path;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
case OSType.MacOS: {
|
|
395
|
+
// Check for Edge first
|
|
396
|
+
const edgePath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
|
|
397
|
+
if (fs.existsSync(edgePath)) {
|
|
398
|
+
return edgePath;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Then check for Chrome
|
|
402
|
+
const chromePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
403
|
+
if (fs.existsSync(chromePath)) {
|
|
404
|
+
return chromePath;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Finally check for Safari
|
|
408
|
+
const safariPath = '/Applications/Safari.app/Contents/MacOS/Safari';
|
|
409
|
+
if (fs.existsSync(safariPath)) {
|
|
410
|
+
return safariPath;
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
case OSType.Linux: {
|
|
416
|
+
// Try Edge first
|
|
417
|
+
try {
|
|
418
|
+
const { stdout: edgePath } = await execAsync('which microsoft-edge');
|
|
419
|
+
if (edgePath.trim()) {
|
|
420
|
+
return edgePath.trim();
|
|
421
|
+
}
|
|
422
|
+
} catch { }
|
|
423
|
+
|
|
424
|
+
// Then try Chrome or Chromium
|
|
425
|
+
try {
|
|
426
|
+
const { stdout: chromePath } = await execAsync('which google-chrome chromium');
|
|
427
|
+
if (chromePath.trim()) {
|
|
428
|
+
return chromePath.trim();
|
|
429
|
+
}
|
|
430
|
+
} catch { }
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// If no browser found, throw error
|
|
436
|
+
throw new Error('No supported browser found on the system');
|
|
437
|
+
} catch (error) {
|
|
438
|
+
Logger.error('Failed to get browser path', error);
|
|
439
|
+
throw error;
|
|
440
|
+
}
|
|
250
441
|
}
|
|
@@ -60,7 +60,7 @@ body {
|
|
|
60
60
|
border: none;
|
|
61
61
|
border-radius: 1rem;
|
|
62
62
|
width: 90%;
|
|
63
|
-
max-width:
|
|
63
|
+
max-width: 900px;
|
|
64
64
|
position: relative;
|
|
65
65
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
66
66
|
transform: translateY(0);
|
|
@@ -117,6 +117,9 @@ body {
|
|
|
117
117
|
/* Sections layout */
|
|
118
118
|
.modal-sections {
|
|
119
119
|
margin-top: 1.5rem;
|
|
120
|
+
display: grid;
|
|
121
|
+
grid-template-columns: 1fr 1fr;
|
|
122
|
+
gap: 1rem;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
.section-container {
|
|
@@ -135,10 +138,16 @@ body {
|
|
|
135
138
|
/* Client grid */
|
|
136
139
|
.client-grid {
|
|
137
140
|
display: grid;
|
|
138
|
-
grid-template-columns: 1fr;
|
|
141
|
+
grid-template-columns: repeat(2, 1fr);
|
|
139
142
|
gap: 0.75rem;
|
|
140
143
|
}
|
|
141
144
|
|
|
145
|
+
/* Make sections take full width */
|
|
146
|
+
.section-container:first-child,
|
|
147
|
+
.section-container:nth-child(2) {
|
|
148
|
+
grid-column: 1 / -1;
|
|
149
|
+
}
|
|
150
|
+
|
|
142
151
|
/* Client item styling */
|
|
143
152
|
.client-item {
|
|
144
153
|
display: flex;
|
|
@@ -221,10 +230,11 @@ body {
|
|
|
221
230
|
/* Environment variables section */
|
|
222
231
|
#modalEnvInputs input {
|
|
223
232
|
width: 100%;
|
|
224
|
-
padding: 0.75rem
|
|
233
|
+
padding: 0.5rem 0.75rem;
|
|
225
234
|
border: 1px solid #e5e7eb;
|
|
226
235
|
border-radius: 0.5rem;
|
|
227
236
|
transition: all 0.2s ease;
|
|
237
|
+
height: 36px;
|
|
228
238
|
}
|
|
229
239
|
|
|
230
240
|
#modalEnvInputs input:focus {
|
|
@@ -233,6 +243,90 @@ body {
|
|
|
233
243
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
234
244
|
}
|
|
235
245
|
|
|
246
|
+
/* Arguments section styling */
|
|
247
|
+
.args-container {
|
|
248
|
+
display: flex;
|
|
249
|
+
flex-direction: column;
|
|
250
|
+
gap: 0.5rem;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.arg-input {
|
|
254
|
+
height: 36px !important;
|
|
255
|
+
padding: 0.5rem 0.75rem !important;
|
|
256
|
+
border: 1px solid #e5e7eb;
|
|
257
|
+
border-radius: 0.5rem;
|
|
258
|
+
transition: all 0.2s ease;
|
|
259
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
260
|
+
font-size: 0.875rem;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.arg-input:focus {
|
|
264
|
+
outline: none;
|
|
265
|
+
border-color: #2563eb;
|
|
266
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.add-arg-button {
|
|
270
|
+
align-self: flex-start;
|
|
271
|
+
display: inline-flex;
|
|
272
|
+
align-items: center;
|
|
273
|
+
gap: 0.25rem;
|
|
274
|
+
height: 32px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.add-arg-button i {
|
|
278
|
+
font-size: 1.25rem;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.remove-arg-button {
|
|
282
|
+
padding: 0.25rem;
|
|
283
|
+
border-radius: 0.375rem;
|
|
284
|
+
transition: all 0.2s ease;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.remove-arg-button:hover {
|
|
288
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.remove-arg-button i {
|
|
292
|
+
font-size: 1.25rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Arguments textarea styling */
|
|
296
|
+
#install_args {
|
|
297
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
298
|
+
font-size: 0.875rem;
|
|
299
|
+
line-height: 1.5;
|
|
300
|
+
resize: vertical;
|
|
301
|
+
transition: all 0.2s ease;
|
|
302
|
+
margin-bottom: 0.5rem;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#install_args:focus {
|
|
306
|
+
outline: none;
|
|
307
|
+
border-color: #2563eb;
|
|
308
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Python environment input styling */
|
|
312
|
+
#python_env {
|
|
313
|
+
height: 36px !important;
|
|
314
|
+
width: 100%;
|
|
315
|
+
padding: 0.75rem 1rem;
|
|
316
|
+
border: 1px solid #e5e7eb;
|
|
317
|
+
border-radius: 0.5rem;
|
|
318
|
+
transition: all 0.2s ease;
|
|
319
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
320
|
+
font-size: 0.875rem;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#python_env:focus {
|
|
324
|
+
outline: none;
|
|
325
|
+
border-color: #2563eb;
|
|
326
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
236
330
|
/* Form buttons */
|
|
237
331
|
.submit-button {
|
|
238
332
|
background-color: #2563eb;
|
|
@@ -97,6 +97,11 @@
|
|
|
97
97
|
<!-- Environment variable inputs will be injected here -->
|
|
98
98
|
</div>
|
|
99
99
|
|
|
100
|
+
<!-- Arguments Section -->
|
|
101
|
+
<div id="modalArguments" class="space-y-4 mb-6">
|
|
102
|
+
<!-- Arguments will be injected here -->
|
|
103
|
+
</div>
|
|
104
|
+
|
|
100
105
|
<div class="flex justify-end space-x-4 mt-6">
|
|
101
106
|
<button type="button" onclick="closeModal()"
|
|
102
107
|
class="px-4 py-2 text-gray-600 hover:text-gray-800 font-medium rounded-md hover:bg-gray-100 transition-colors">
|
|
@@ -151,10 +156,24 @@
|
|
|
151
156
|
window.uninstallTool = uninstallTool;
|
|
152
157
|
|
|
153
158
|
// Initialize
|
|
154
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
159
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
155
160
|
setupSearch();
|
|
156
161
|
setupModalOutsideClick();
|
|
157
|
-
|
|
162
|
+
|
|
163
|
+
// Check URL parameters for category
|
|
164
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
165
|
+
const categoryParam = urlParams.get('category');
|
|
166
|
+
|
|
167
|
+
// If we have a category parameter or last selected category
|
|
168
|
+
const lastSelected = categoryParam || localStorage.getItem('lastSelectedCategory');
|
|
169
|
+
|
|
170
|
+
// First fetch categories
|
|
171
|
+
await fetchServerCategories();
|
|
172
|
+
|
|
173
|
+
// Then show the selected category if it exists
|
|
174
|
+
if (lastSelected) {
|
|
175
|
+
showServerDetails(lastSelected);
|
|
176
|
+
}
|
|
158
177
|
});
|
|
159
178
|
</script>
|
|
160
179
|
<script src="js/modal.js" type="module"></script>
|