opencode-azure-setup 1.0.2 → 1.0.3

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 +129 -41
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -37,6 +37,36 @@ function getConfigPath() {
37
37
  return path.join(os.homedir(), '.config', 'opencode', 'opencode.json');
38
38
  }
39
39
 
40
+ // Load existing config if it exists
41
+ function loadExistingConfig() {
42
+ const configPath = getConfigPath();
43
+ try {
44
+ if (fs.existsSync(configPath)) {
45
+ const content = fs.readFileSync(configPath, 'utf-8');
46
+ return JSON.parse(content);
47
+ }
48
+ } catch {
49
+ // Config doesn't exist or is invalid
50
+ }
51
+ return null;
52
+ }
53
+
54
+ // Extract existing Azure settings from config
55
+ function getExistingAzureSettings(config) {
56
+ if (!config?.provider?.azure?.options) return null;
57
+
58
+ const azure = config.provider.azure;
59
+ const opts = azure.options;
60
+ const modelName = Object.keys(azure.models || {})[0] || 'model-router';
61
+
62
+ return {
63
+ baseUrl: opts.baseURL || '',
64
+ apiKey: opts.apiKey || '',
65
+ deployment: modelName,
66
+ apiVersion: opts.apiVersion || '2025-01-01-preview',
67
+ };
68
+ }
69
+
40
70
  const rl = readline.createInterface({
41
71
  input: process.stdin,
42
72
  output: process.stdout,
@@ -49,9 +79,15 @@ function ask(question, defaultValue = '') {
49
79
  });
50
80
  }
51
81
 
52
- function askPassword(question) {
82
+ function askPassword(question, existingValue = '') {
53
83
  return new Promise((resolve) => {
54
- process.stdout.write(`${question}: `);
84
+ if (existingValue) {
85
+ const masked = existingValue.slice(0, 4) + '...' + existingValue.slice(-4);
86
+ process.stdout.write(`${question} [${masked}]: `);
87
+ } else {
88
+ process.stdout.write(`${question}: `);
89
+ }
90
+
55
91
  if (process.stdin.isTTY) {
56
92
  const stdin = process.stdin;
57
93
  stdin.setRawMode(true);
@@ -63,7 +99,8 @@ function askPassword(question) {
63
99
  stdin.setRawMode(false);
64
100
  stdin.removeListener('data', onData);
65
101
  console.log();
66
- resolve(password);
102
+ // If user just pressed Enter and there's an existing value, use it
103
+ resolve(password || existingValue);
67
104
  } else if (char === '\u0003') {
68
105
  process.exit();
69
106
  } else if (char === '\u007F' || char === '\b') {
@@ -74,7 +111,7 @@ function askPassword(question) {
74
111
  };
75
112
  stdin.on('data', onData);
76
113
  } else {
77
- rl.question('', resolve);
114
+ rl.question('', (answer) => resolve(answer || existingValue));
78
115
  }
79
116
  });
80
117
  }
@@ -193,40 +230,77 @@ async function main() {
193
230
  console.log('─'.repeat(40));
194
231
  console.log();
195
232
 
233
+ // Load existing config
234
+ const existingConfig = loadExistingConfig();
235
+ const existingAzure = getExistingAzureSettings(existingConfig);
236
+
196
237
  // Fetch latest defaults (non-blocking, falls back to hardcoded)
197
238
  const defaults = await fetchDefaults();
198
239
 
240
+ // If existing config found, show current values
241
+ if (existingAzure && existingAzure.baseUrl) {
242
+ 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);
244
+ console.log();
245
+ }
246
+
199
247
  // Endpoint - accepts full URL or just the base
200
- console.log('Paste your Azure OpenAI endpoint');
201
- console.log(colors.dim + 'Tip: You can paste the full URL from Azure Portal - we\'ll extract what we need' + colors.reset);
202
- console.log();
203
- const rawEndpoint = await ask('Endpoint');
248
+ let baseUrl, deployment, apiVersion;
204
249
 
205
- if (!rawEndpoint) {
206
- console.log(colors.red + 'Endpoint is required' + colors.reset);
207
- process.exit(1);
208
- }
250
+ if (existingAzure?.baseUrl) {
251
+ console.log('Azure OpenAI Endpoint');
252
+ const rawEndpoint = await ask('Endpoint', existingAzure.baseUrl);
253
+
254
+ if (rawEndpoint === existingAzure.baseUrl) {
255
+ // User kept existing - use existing parsed values
256
+ baseUrl = existingAzure.baseUrl;
257
+ deployment = existingAzure.deployment;
258
+ apiVersion = existingAzure.apiVersion;
259
+ } else {
260
+ // User entered new value - parse it
261
+ const parsed = parseAzureEndpoint(rawEndpoint, defaults);
262
+ baseUrl = parsed.baseUrl;
263
+ deployment = parsed.deployment;
264
+ apiVersion = parsed.apiVersion;
265
+ }
266
+ } else {
267
+ console.log('Paste your Azure OpenAI endpoint');
268
+ console.log(colors.dim + 'Tip: You can paste the full URL from Azure Portal - we\'ll extract what we need' + colors.reset);
269
+ console.log();
270
+ const rawEndpoint = await ask('Endpoint');
209
271
 
210
- // Parse the endpoint - extracts base URL, deployment, and api-version automatically
211
- const parsed = parseAzureEndpoint(rawEndpoint, defaults);
272
+ if (!rawEndpoint) {
273
+ console.log(colors.red + 'Endpoint is required' + colors.reset);
274
+ process.exit(1);
275
+ }
276
+
277
+ const parsed = parseAzureEndpoint(rawEndpoint, defaults);
278
+ baseUrl = parsed.baseUrl;
279
+ deployment = parsed.deployment;
280
+ apiVersion = parsed.apiVersion;
281
+ }
212
282
 
213
283
  // API Key
214
284
  console.log();
215
- const apiKey = await askPassword('API Key');
285
+ const apiKey = await askPassword('API Key', existingAzure?.apiKey || '');
216
286
  if (!apiKey) {
217
287
  console.log(colors.red + 'API Key is required' + colors.reset);
218
288
  process.exit(1);
219
289
  }
220
290
 
221
- // Use auto-detected values
222
- let deployment = parsed.deployment;
223
- let apiVersion = parsed.apiVersion;
291
+ // Deployment (only ask if not using existing)
292
+ if (existingAzure?.deployment && deployment === existingAzure.deployment) {
293
+ // Keep existing
294
+ } else {
295
+ console.log();
296
+ deployment = await ask('Deployment name', deployment);
297
+ }
224
298
 
225
299
  console.log();
226
300
  console.log(colors.blue + 'Testing connection...' + colors.reset);
227
- console.log(colors.dim + ` ${parsed.baseUrl}/deployments/${deployment}` + colors.reset);
301
+ console.log(colors.dim + ` ${baseUrl}/deployments/${deployment}` + colors.reset);
228
302
 
229
- let result = await testConnection(parsed.baseUrl, apiKey, deployment, apiVersion);
303
+ let result = await testConnection(baseUrl, apiKey, deployment, apiVersion);
230
304
 
231
305
  if (result.ok) {
232
306
  console.log(colors.green + '✓ Connection successful!' + colors.reset);
@@ -249,7 +323,7 @@ async function main() {
249
323
 
250
324
  console.log();
251
325
  console.log(colors.blue + 'Retrying...' + colors.reset);
252
- result = await testConnection(parsed.baseUrl, apiKey, deployment, apiVersion);
326
+ result = await testConnection(baseUrl, apiKey, deployment, apiVersion);
253
327
 
254
328
  if (result.ok) {
255
329
  console.log(colors.green + '✓ Connection successful!' + colors.reset);
@@ -260,29 +334,32 @@ async function main() {
260
334
  }
261
335
  }
262
336
 
263
- // Create config
337
+ // Create config - preserve existing settings like agents, permissions
264
338
  const configPath = getConfigPath();
265
339
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
266
340
 
267
- const config = {
268
- $schema: 'https://opencode.ai/config.json',
269
- model: `azure/${deployment}`,
270
- provider: {
271
- azure: {
272
- npm: '@ai-sdk/azure',
273
- name: 'Azure OpenAI',
274
- options: {
275
- baseURL: parsed.baseUrl,
276
- apiKey: apiKey,
277
- useDeploymentBasedUrls: true,
278
- apiVersion: apiVersion,
279
- },
280
- models: {
281
- [deployment]: {
282
- name: deployment,
283
- limit: { context: 200000, output: 16384 },
284
- },
285
- },
341
+ // Start with existing config or empty object
342
+ const config = existingConfig || {};
343
+
344
+ // Update schema and model
345
+ config.$schema = 'https://opencode.ai/config.json';
346
+ config.model = `azure/${deployment}`;
347
+
348
+ // Update Azure provider settings
349
+ config.provider = config.provider || {};
350
+ config.provider.azure = {
351
+ npm: '@ai-sdk/azure',
352
+ name: 'Azure OpenAI',
353
+ options: {
354
+ baseURL: baseUrl,
355
+ apiKey: apiKey,
356
+ useDeploymentBasedUrls: true,
357
+ apiVersion: apiVersion,
358
+ },
359
+ models: {
360
+ [deployment]: {
361
+ name: deployment,
362
+ limit: { context: 200000, output: 16384 },
286
363
  },
287
364
  },
288
365
  };
@@ -292,6 +369,17 @@ async function main() {
292
369
  console.log();
293
370
  console.log(colors.green + '✓ Configuration saved!' + colors.reset);
294
371
  console.log(colors.dim + ` ${configPath}` + colors.reset);
372
+
373
+ // Show what was preserved
374
+ if (existingConfig) {
375
+ const preserved = [];
376
+ if (existingConfig.agent) preserved.push('agents');
377
+ if (existingConfig.permission) preserved.push('permissions');
378
+ if (preserved.length > 0) {
379
+ console.log(colors.dim + ` Preserved: ${preserved.join(', ')}` + colors.reset);
380
+ }
381
+ }
382
+
295
383
  console.log();
296
384
  console.log('─'.repeat(40));
297
385
  console.log(colors.green + 'You\'re all set! Run:' + colors.reset);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-azure-setup",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Easy Azure OpenAI setup for OpenCode",
5
5
  "type": "module",
6
6
  "main": "index.js",