coder-agent 2.8.1 → 2.8.2

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/dist/agent.js CHANGED
@@ -563,6 +563,12 @@ export class Agent {
563
563
  setModel(model) {
564
564
  this.model = model;
565
565
  }
566
+ getApiKey() {
567
+ return this.apiKey;
568
+ }
569
+ setApiKey(key) {
570
+ this.apiKey = key;
571
+ }
566
572
  async chat(userMessage, signal) {
567
573
  try {
568
574
  if (signal?.aborted) {
package/dist/index.js CHANGED
@@ -180,9 +180,15 @@ async function main() {
180
180
  console.log(chalk.dim(`✓ Default model set to: ${tempModel}`));
181
181
  process.exit(0);
182
182
  }
183
- // Bootstrap API Key if missing
184
- if (!apiKey) {
185
- apiKey = await promptApiKey();
183
+ // Load API Key
184
+ apiKey = apiKey || "";
185
+ // Single-Shot Mode key check
186
+ if (queryArgs.length > 0 && !apiKey) {
187
+ console.log(chalk.hex('#ff453a')('✕ error'));
188
+ console.log(chalk.dim(" Gemini API Key is required but missing."));
189
+ console.log(chalk.dim(" Please set it using the GEMINI_API_KEY environment variable or run:"));
190
+ console.log(` ${chalk.cyan("coder-agent --set-key <key>")}`);
191
+ process.exit(1);
186
192
  }
187
193
  let currentAbortController = null;
188
194
  let originalListeners = [];
@@ -279,7 +285,12 @@ async function main() {
279
285
  // Save/update last used info immediately
280
286
  await saveLastUsedInfo(CURRENT_VERSION, Date.now());
281
287
  printBanner(modelToUse);
282
- if (showWelcomeCommands) {
288
+ if (!agent.getApiKey()) {
289
+ console.log(chalk.hex('#ff9f0a')(' 🔑 Gemini API Key is missing!'));
290
+ console.log(` Please type ${chalk.cyan('/key <your_api_key>')} to set and save it globally.`);
291
+ console.log(chalk.dim(" Get a free key at https://aistudio.google.com\n"));
292
+ }
293
+ else if (showWelcomeCommands) {
283
294
  console.log(chalk.white.bold(" 💡 Get started with interactive slash commands:"));
284
295
  console.log(` ${chalk.hex('#0a84ff')('/model')} ${chalk.gray('[name]')} — View active model or switch to [name]`);
285
296
  console.log(` ${chalk.hex('#0a84ff')('/clear')} — Wipe conversation memory`);
@@ -288,11 +299,15 @@ async function main() {
288
299
  console.log(` ${chalk.hex('#0a84ff')('/exit')} — Exit Coder`);
289
300
  console.log();
290
301
  }
302
+ let isRlClosed = false;
291
303
  rl = readline.createInterface({
292
304
  input: process.stdin,
293
305
  output: process.stdout,
294
306
  terminal: true,
295
307
  });
308
+ rl.on("close", () => {
309
+ isRlClosed = true;
310
+ });
296
311
  process.stdin.on("keypress", (char, key) => {
297
312
  if (isHijacked || !rl)
298
313
  return;
@@ -301,6 +316,7 @@ async function main() {
301
316
  console.log();
302
317
  console.log(chalk.dim(" Available Commands:"));
303
318
  console.log(` ${chalk.hex('#0a84ff')('/model')} ${chalk.gray('[name]')} ${chalk.dim('— View active model or switch to [name]')}`);
319
+ console.log(` ${chalk.hex('#0a84ff')('/key')} ${chalk.gray('[api_key]')} ${chalk.dim('— Set/save your Gemini API Key globally')}`);
304
320
  console.log(` ${chalk.hex('#0a84ff')('/clear')} ${chalk.dim('— Wipe conversation memory')}`);
305
321
  console.log(` ${chalk.hex('#0a84ff')('/status')} ${chalk.dim('— Show active model and memory usage')}`);
306
322
  console.log(` ${chalk.hex('#0a84ff')('/help')} ${chalk.dim('— Show help screen')}`);
@@ -314,24 +330,42 @@ async function main() {
314
330
  let pasteTimeout = null;
315
331
  let lineCountInBurst = 0;
316
332
  async function executeAgentChat(trimmed) {
333
+ if (isRlClosed)
334
+ return;
317
335
  // Pause standard input processing during agent thinking & updates
318
- rl.pause();
336
+ try {
337
+ rl.pause();
338
+ }
339
+ catch { }
319
340
  // Built-in slash commands
320
341
  if (trimmed === "/exit" || trimmed === "/quit") {
321
- rl.close();
342
+ try {
343
+ rl.close();
344
+ }
345
+ catch { }
322
346
  process.exit(0);
323
347
  }
324
348
  if (trimmed === "/clear") {
325
349
  agent.clearMemory();
326
350
  console.log(chalk.hex('#30d158')('✓') + ' ' + chalk.gray('Memory cleared'));
327
- rl.resume();
328
- rl.prompt();
351
+ if (!isRlClosed) {
352
+ try {
353
+ rl.resume();
354
+ rl.prompt();
355
+ }
356
+ catch { }
357
+ }
329
358
  return;
330
359
  }
331
360
  if (trimmed === "/status") {
332
361
  console.log(chalk.dim(`session · ${agent.memoryStatus()}`));
333
- rl.resume();
334
- rl.prompt();
362
+ if (!isRlClosed) {
363
+ try {
364
+ rl.resume();
365
+ rl.prompt();
366
+ }
367
+ catch { }
368
+ }
335
369
  return;
336
370
  }
337
371
  if (trimmed.startsWith("/model")) {
@@ -351,22 +385,77 @@ async function main() {
351
385
  console.log(chalk.dim(` Model must be one of: ${VALID_MODELS.join(" · ")}`));
352
386
  }
353
387
  }
354
- rl.resume();
355
- rl.prompt();
388
+ if (!isRlClosed) {
389
+ try {
390
+ rl.resume();
391
+ rl.prompt();
392
+ }
393
+ catch { }
394
+ }
395
+ return;
396
+ }
397
+ if (trimmed.startsWith("/key")) {
398
+ const parts = trimmed.split(/\s+/);
399
+ if (parts.length === 1) {
400
+ const keyToCheck = agent.getApiKey();
401
+ if (keyToCheck) {
402
+ const masked = keyToCheck.slice(0, 7) + "..." + keyToCheck.slice(-4);
403
+ console.log(chalk.dim(` Gemini API Key is set: `) + chalk.gray(masked));
404
+ }
405
+ else {
406
+ console.log(chalk.hex('#ff453a')('✕ error') + chalk.dim(' — Gemini API Key is missing. Set it using: /key <your_api_key>'));
407
+ }
408
+ }
409
+ else {
410
+ const newKey = parts[1].trim();
411
+ if (!newKey) {
412
+ console.log(chalk.hex('#ff453a')('✕ error') + chalk.dim(' — API Key cannot be empty.'));
413
+ }
414
+ else {
415
+ await saveApiKey(newKey);
416
+ agent.setApiKey(newKey);
417
+ console.log(chalk.hex('#30d158')('✓') + ' ' + chalk.gray('Gemini API Key saved and set successfully.'));
418
+ }
419
+ }
420
+ if (!isRlClosed) {
421
+ try {
422
+ rl.resume();
423
+ rl.prompt();
424
+ }
425
+ catch { }
426
+ }
356
427
  return;
357
428
  }
358
429
  if (trimmed === "/help") {
359
430
  console.log(chalk.white.bold("\n Interactive Commands:"));
360
431
  console.log(chalk.gray(` /model [name] — View active model or switch to [name]
432
+ /key [api_key]— Set/save your Gemini API Key globally (hides the key from the LLM)
361
433
  /clear — Wipe conversation memory
362
434
  /status — Show active model and memory usage
363
435
  /exit — Exit Coder`));
364
436
  console.log(chalk.white.bold("\n API Keys & Configuration:"));
365
437
  console.log(chalk.gray(` • Stored at: ~/.coder-config.json
366
- • To change key: Exit and run 'coder-agent --set-key <key>'
438
+ • To change key: Type '/key <api_key>' or run 'coder-agent --set-key <key>'
367
439
  • Env variable option: GEMINI_API_KEY`));
368
- rl.resume();
369
- rl.prompt();
440
+ if (!isRlClosed) {
441
+ try {
442
+ rl.resume();
443
+ rl.prompt();
444
+ }
445
+ catch { }
446
+ }
447
+ return;
448
+ }
449
+ // Block logic execution if API Key is missing
450
+ if (!agent.getApiKey()) {
451
+ console.log(chalk.hex('#ff453a')('✕ error') + chalk.dim(' — Gemini API Key is missing. Please set it using: /key <your_api_key>'));
452
+ if (!isRlClosed) {
453
+ try {
454
+ rl.resume();
455
+ rl.prompt();
456
+ }
457
+ catch { }
458
+ }
370
459
  return;
371
460
  }
372
461
  currentAbortController = new AbortController();
@@ -395,9 +484,14 @@ async function main() {
395
484
  stopHijack();
396
485
  currentAbortController = null;
397
486
  }
398
- rl.resume();
399
- console.log(chalk.dim('────────────────────────────────────────────────'));
400
- rl.prompt();
487
+ if (!isRlClosed) {
488
+ try {
489
+ rl.resume();
490
+ console.log(chalk.dim('────────────────────────────────────────────────'));
491
+ rl.prompt();
492
+ }
493
+ catch { }
494
+ }
401
495
  }
402
496
  console.log(chalk.dim('────────────────────────────────────────────────'));
403
497
  rl.setPrompt(chalk.hex('#0a84ff')('›') + ' ');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coder-agent",
3
- "version": "2.8.1",
3
+ "version": "2.8.2",
4
4
  "description": "CLI coding agent powered by Google Gemini",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",