opencode-azure-setup 1.0.4 → 1.0.6

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 (2) hide show
  1. package/index.js +91 -43
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * Usage:
7
7
  * npx opencode-azure-setup
8
+ * npx opencode-azure-setup -y # Non-interactive (use existing config)
8
9
  * node install-azure.js
9
10
  */
10
11
 
@@ -14,6 +15,10 @@ import readline from 'readline';
14
15
  import https from 'https';
15
16
  import os from 'os';
16
17
 
18
+ // Parse args
19
+ const args = process.argv.slice(2);
20
+ const nonInteractive = args.includes('-y') || args.includes('--yes') || args.includes('--non-interactive');
21
+
17
22
  // Colors
18
23
  const colors = {
19
24
  blue: '\x1b[34m',
@@ -67,15 +72,22 @@ function getExistingAzureSettings(config) {
67
72
  };
68
73
  }
69
74
 
70
- const rl = readline.createInterface({
71
- input: process.stdin,
72
- output: process.stdout,
73
- });
75
+ // Only create readline interface if not in non-interactive mode
76
+ let rl = null;
77
+ function getRl() {
78
+ if (!rl) {
79
+ rl = readline.createInterface({
80
+ input: process.stdin,
81
+ output: process.stdout,
82
+ });
83
+ }
84
+ return rl;
85
+ }
74
86
 
75
87
  function ask(question, defaultValue = '') {
76
88
  return new Promise((resolve) => {
77
89
  const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
78
- rl.question(prompt, (answer) => resolve(answer || defaultValue));
90
+ getRl().question(prompt, (answer) => resolve(answer || defaultValue));
79
91
  });
80
92
  }
81
93
 
@@ -240,14 +252,29 @@ async function main() {
240
252
  // If existing config found, show current values
241
253
  if (existingAzure && existingAzure.baseUrl) {
242
254
  console.log(colors.green + '✓ Existing configuration found' + colors.reset);
243
- console.log(colors.dim + ' Press Enter to keep current values, or type new ones' + colors.reset);
255
+ if (nonInteractive) {
256
+ console.log(colors.dim + ' Using existing values (non-interactive mode)' + colors.reset);
257
+ } else {
258
+ console.log(colors.dim + ' Press Enter to keep current values, or type new ones' + colors.reset);
259
+ }
244
260
  console.log();
245
261
  }
246
262
 
247
263
  // Endpoint - accepts full URL or just the base
248
- let baseUrl, deployment, apiVersion;
249
-
250
- if (existingAzure?.baseUrl) {
264
+ let baseUrl, deployment, apiVersion, apiKey;
265
+
266
+ // Non-interactive mode with existing config - skip all prompts
267
+ if (nonInteractive && existingAzure?.baseUrl && existingAzure?.apiKey) {
268
+ baseUrl = existingAzure.baseUrl;
269
+ deployment = existingAzure.deployment;
270
+ apiVersion = existingAzure.apiVersion;
271
+ apiKey = existingAzure.apiKey;
272
+ console.log(colors.dim + ` Endpoint: ${baseUrl}` + colors.reset);
273
+ console.log(colors.dim + ` Deployment: ${deployment}` + colors.reset);
274
+ } else if (nonInteractive && !existingAzure?.baseUrl) {
275
+ console.log(colors.red + 'No existing config found. Run without -y flag to configure.' + colors.reset);
276
+ process.exit(1);
277
+ } else if (existingAzure?.baseUrl) {
251
278
  console.log('Azure OpenAI Endpoint');
252
279
  const rawEndpoint = await ask('Endpoint', existingAzure.baseUrl);
253
280
 
@@ -263,6 +290,22 @@ async function main() {
263
290
  deployment = parsed.deployment;
264
291
  apiVersion = parsed.apiVersion;
265
292
  }
293
+
294
+ // API Key
295
+ console.log();
296
+ apiKey = await askPassword('API Key', existingAzure?.apiKey || '');
297
+ if (!apiKey) {
298
+ console.log(colors.red + 'API Key is required' + colors.reset);
299
+ process.exit(1);
300
+ }
301
+
302
+ // Deployment (only ask if not using existing)
303
+ if (existingAzure?.deployment && deployment === existingAzure.deployment) {
304
+ // Keep existing
305
+ } else {
306
+ console.log();
307
+ deployment = await ask('Deployment name', deployment);
308
+ }
266
309
  } else {
267
310
  console.log('Paste your Azure OpenAI endpoint');
268
311
  console.log(colors.dim + 'Tip: You can paste the full URL from Azure Portal - we\'ll extract what we need' + colors.reset);
@@ -278,20 +321,15 @@ async function main() {
278
321
  baseUrl = parsed.baseUrl;
279
322
  deployment = parsed.deployment;
280
323
  apiVersion = parsed.apiVersion;
281
- }
282
324
 
283
- // API Key
284
- console.log();
285
- const apiKey = await askPassword('API Key', existingAzure?.apiKey || '');
286
- if (!apiKey) {
287
- console.log(colors.red + 'API Key is required' + colors.reset);
288
- process.exit(1);
289
- }
325
+ // API Key
326
+ console.log();
327
+ apiKey = await askPassword('API Key');
328
+ if (!apiKey) {
329
+ console.log(colors.red + 'API Key is required' + colors.reset);
330
+ process.exit(1);
331
+ }
290
332
 
291
- // Deployment (only ask if not using existing)
292
- if (existingAzure?.deployment && deployment === existingAzure.deployment) {
293
- // Keep existing
294
- } else {
295
333
  console.log();
296
334
  deployment = await ask('Deployment name', deployment);
297
335
  }
@@ -315,22 +353,27 @@ async function main() {
315
353
  }
316
354
  }
317
355
 
318
- // Offer to edit settings if connection failed
319
- console.log();
320
- console.log(colors.yellow + 'Let\'s try different settings:' + colors.reset);
321
- deployment = await ask('Deployment name', deployment);
322
- apiVersion = await ask('API Version', apiVersion);
323
-
324
- console.log();
325
- console.log(colors.blue + 'Retrying...' + colors.reset);
326
- result = await testConnection(baseUrl, apiKey, deployment, apiVersion);
327
-
328
- if (result.ok) {
329
- console.log(colors.green + '✓ Connection successful!' + colors.reset);
356
+ if (nonInteractive) {
357
+ // Non-interactive mode - just continue with existing config
358
+ console.log(colors.yellow + ' Continuing anyway (non-interactive mode)' + colors.reset);
330
359
  } else {
331
- console.log(colors.red + `✗ Still failing (${result.status || 'error'})` + colors.reset);
332
- const cont = await ask('Save config anyway? (y/N)', 'N');
333
- if (cont.toLowerCase() !== 'y') process.exit(1);
360
+ // Offer to edit settings if connection failed
361
+ console.log();
362
+ console.log(colors.yellow + 'Let\'s try different settings:' + colors.reset);
363
+ deployment = await ask('Deployment name', deployment);
364
+ apiVersion = await ask('API Version', apiVersion);
365
+
366
+ console.log();
367
+ console.log(colors.blue + 'Retrying...' + colors.reset);
368
+ result = await testConnection(baseUrl, apiKey, deployment, apiVersion);
369
+
370
+ if (result.ok) {
371
+ console.log(colors.green + '✓ Connection successful!' + colors.reset);
372
+ } else {
373
+ console.log(colors.red + `✗ Still failing (${result.status || 'error'})` + colors.reset);
374
+ const cont = await ask('Save config anyway? (y/N)', 'N');
375
+ if (cont.toLowerCase() !== 'y') process.exit(1);
376
+ }
334
377
  }
335
378
  }
336
379
 
@@ -368,18 +411,22 @@ async function main() {
368
411
  console.log();
369
412
  console.log(colors.blue + 'Setting up MCP Marketplace...' + colors.reset);
370
413
 
371
- const mcpDir = path.join(os.homedir(), '.config', 'opencode', 'mcps');
414
+ const mcpDir = path.join(os.homedir(), '.config', 'opencode', 'mcps', 'mcp-marketplace');
372
415
  fs.mkdirSync(mcpDir, { recursive: true });
373
416
 
374
417
  try {
375
418
  const { execFileSync } = await import('child_process');
376
419
 
377
- // Install mcp-marketplace package globally
378
- execFileSync('npm', ['install', '-g', 'opencode-mcp-marketplace'], { stdio: 'pipe' });
420
+ // Initialize package.json if not exists
421
+ const pkgPath = path.join(mcpDir, 'package.json');
422
+ if (!fs.existsSync(pkgPath)) {
423
+ fs.writeFileSync(pkgPath, JSON.stringify({ name: 'opencode-mcps', version: '1.0.0', type: 'module' }, null, 2));
424
+ }
425
+
426
+ // Install mcp-marketplace package locally (no sudo needed)
427
+ execFileSync('npm', ['install', 'opencode-mcp-marketplace@latest'], { cwd: mcpDir, stdio: 'pipe' });
379
428
 
380
- // Find the installed package path
381
- const npmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf-8' }).trim();
382
- const mcpPath = path.join(npmRoot, 'opencode-mcp-marketplace', 'dist', 'index.js');
429
+ const mcpPath = path.join(mcpDir, 'node_modules', 'opencode-mcp-marketplace', 'dist', 'index.js');
383
430
 
384
431
  // Add to config
385
432
  config.mcp = config.mcp || {};
@@ -391,6 +438,7 @@ async function main() {
391
438
  console.log(colors.green + '✓ MCP Marketplace installed!' + colors.reset);
392
439
  } catch (e) {
393
440
  console.log(colors.yellow + '⚠ MCP Marketplace install skipped (npm not available or failed)' + colors.reset);
441
+ console.log(colors.dim + ' You can install manually: npm install -g opencode-mcp-marketplace' + colors.reset);
394
442
  }
395
443
 
396
444
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
@@ -416,7 +464,7 @@ async function main() {
416
464
  console.log(' ' + colors.blue + 'opencode' + colors.reset);
417
465
  console.log();
418
466
 
419
- rl.close();
467
+ if (rl) rl.close();
420
468
  }
421
469
 
422
470
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-azure-setup",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Easy Azure OpenAI setup for OpenCode",
5
5
  "type": "module",
6
6
  "main": "index.js",