archondev 1.1.0 → 1.2.0

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.
@@ -2,8 +2,8 @@ import {
2
2
  bugReport
3
3
  } from "./chunk-JBKFAD4M.js";
4
4
  import "./chunk-MOZHC2GX.js";
5
- import "./chunk-WCCBJSNI.js";
6
5
  import "./chunk-A7QU6JC6.js";
6
+ import "./chunk-WCCBJSNI.js";
7
7
  import "./chunk-QGM4M3NI.js";
8
8
  export {
9
9
  bugReport
@@ -6,19 +6,22 @@ import {
6
6
  createAtom,
7
7
  validateAtom
8
8
  } from "./chunk-MOZHC2GX.js";
9
- import {
10
- isAuthenticated
11
- } from "./chunk-WCCBJSNI.js";
12
9
  import {
13
10
  AnthropicClient,
14
11
  getDefaultModel
15
12
  } from "./chunk-A7QU6JC6.js";
13
+ import {
14
+ KeyManager
15
+ } from "./chunk-SMR7JQK6.js";
16
+ import {
17
+ isAuthenticated
18
+ } from "./chunk-WCCBJSNI.js";
16
19
 
17
20
  // src/cli/plan.ts
18
21
  import chalk from "chalk";
19
- import { existsSync as existsSync2 } from "fs";
20
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
21
- import { join as join2 } from "path";
22
+ import { existsSync } from "fs";
23
+ import { readFile, writeFile, mkdir } from "fs/promises";
24
+ import { join } from "path";
22
25
  import { createInterface } from "readline";
23
26
 
24
27
  // src/agents/sentinel.ts
@@ -277,400 +280,6 @@ var AdversarialPlanner = class {
277
280
  }
278
281
  };
279
282
 
280
- // src/core/keys/manager.ts
281
- import { homedir as homedir2 } from "os";
282
- import { join } from "path";
283
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
284
- import { existsSync } from "fs";
285
-
286
- // src/core/keys/encryption.ts
287
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
288
- import { homedir, hostname, userInfo } from "os";
289
- var ALGORITHM = "aes-256-gcm";
290
- var IV_LENGTH = 16;
291
- var AUTH_TAG_LENGTH = 16;
292
- var SALT_LENGTH = 32;
293
- var KEY_LENGTH = 32;
294
- function getDerivedKey(salt) {
295
- const machineId = `${hostname()}-${userInfo().username}-${homedir()}`;
296
- return scryptSync(machineId, salt, KEY_LENGTH);
297
- }
298
- function encrypt(plaintext) {
299
- const salt = randomBytes(SALT_LENGTH);
300
- const key = getDerivedKey(salt);
301
- const iv = randomBytes(IV_LENGTH);
302
- const cipher = createCipheriv(ALGORITHM, key, iv);
303
- let encrypted = cipher.update(plaintext, "utf8", "hex");
304
- encrypted += cipher.final("hex");
305
- const authTag = cipher.getAuthTag();
306
- const combined = Buffer.concat([
307
- salt,
308
- iv,
309
- authTag,
310
- Buffer.from(encrypted, "hex")
311
- ]);
312
- return combined.toString("base64");
313
- }
314
- function decrypt(encryptedData) {
315
- const combined = Buffer.from(encryptedData, "base64");
316
- const salt = combined.subarray(0, SALT_LENGTH);
317
- const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
318
- const authTag = combined.subarray(
319
- SALT_LENGTH + IV_LENGTH,
320
- SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH
321
- );
322
- const encrypted = combined.subarray(SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);
323
- const key = getDerivedKey(salt);
324
- const decipher = createDecipheriv(ALGORITHM, key, iv);
325
- decipher.setAuthTag(authTag);
326
- let decrypted = decipher.update(encrypted.toString("hex"), "hex", "utf8");
327
- decrypted += decipher.final("utf8");
328
- return decrypted;
329
- }
330
-
331
- // src/core/keys/manager.ts
332
- var CONFIG_DIR = join(homedir2(), ".archon");
333
- var KEYS_FILE = join(CONFIG_DIR, "keys.json");
334
- var CURRENT_VERSION = 2;
335
- var KeyManager = class {
336
- async ensureConfigDir() {
337
- if (!existsSync(CONFIG_DIR)) {
338
- await mkdir(CONFIG_DIR, { recursive: true, mode: 448 });
339
- }
340
- }
341
- async loadKeys() {
342
- try {
343
- if (!existsSync(KEYS_FILE)) {
344
- return { keys: [], version: CURRENT_VERSION };
345
- }
346
- const content = await readFile(KEYS_FILE, "utf-8");
347
- const data = JSON.parse(content);
348
- if (data.version === 1 && !Array.isArray(data.keys)) {
349
- const oldKeys = data.keys;
350
- const newKeys = Object.values(oldKeys).map((k) => ({
351
- ...k,
352
- label: k.label ?? "default",
353
- isPrimary: k.isPrimary ?? true
354
- }));
355
- const migrated = { keys: newKeys, version: CURRENT_VERSION };
356
- await this.saveKeys(migrated);
357
- return migrated;
358
- }
359
- return data;
360
- } catch {
361
- return { keys: [], version: CURRENT_VERSION };
362
- }
363
- }
364
- async saveKeys(stored) {
365
- await this.ensureConfigDir();
366
- const content = JSON.stringify(stored, null, 2);
367
- await writeFile(KEYS_FILE, content, { mode: 384 });
368
- await chmod(KEYS_FILE, 384);
369
- }
370
- async addKey(provider, apiKey, label = "default") {
371
- try {
372
- const stored = await this.loadKeys();
373
- const now = (/* @__PURE__ */ new Date()).toISOString();
374
- const existingIndex = stored.keys.findIndex((k) => k.provider === provider && k.label === label);
375
- const providerKeys = stored.keys.filter((k) => k.provider === provider);
376
- const isPrimary = providerKeys.length === 0 || existingIndex >= 0 && stored.keys[existingIndex]?.isPrimary === true;
377
- const newKey = {
378
- provider,
379
- encryptedKey: encrypt(apiKey),
380
- label,
381
- isPrimary,
382
- createdAt: now,
383
- updatedAt: now
384
- };
385
- if (existingIndex >= 0) {
386
- const existing = stored.keys[existingIndex];
387
- if (existing) {
388
- newKey.createdAt = existing.createdAt;
389
- newKey.isPrimary = existing.isPrimary;
390
- }
391
- stored.keys[existingIndex] = newKey;
392
- } else {
393
- stored.keys.push(newKey);
394
- }
395
- await this.saveKeys(stored);
396
- return { success: true };
397
- } catch (error) {
398
- return {
399
- success: false,
400
- error: `Failed to save key: ${error instanceof Error ? error.message : "Unknown error"}`
401
- };
402
- }
403
- }
404
- async getKey(provider, label) {
405
- try {
406
- const stored = await this.loadKeys();
407
- let keyConfig;
408
- if (label) {
409
- keyConfig = stored.keys.find((k) => k.provider === provider && k.label === label);
410
- } else {
411
- keyConfig = stored.keys.find((k) => k.provider === provider && k.isPrimary);
412
- if (!keyConfig) {
413
- keyConfig = stored.keys.find((k) => k.provider === provider);
414
- }
415
- }
416
- if (!keyConfig) {
417
- return null;
418
- }
419
- return decrypt(keyConfig.encryptedKey);
420
- } catch {
421
- return null;
422
- }
423
- }
424
- async removeKey(provider, label) {
425
- try {
426
- const stored = await this.loadKeys();
427
- let index;
428
- if (label) {
429
- index = stored.keys.findIndex((k) => k.provider === provider && k.label === label);
430
- } else {
431
- index = stored.keys.findIndex((k) => k.provider === provider && k.isPrimary);
432
- if (index < 0) {
433
- index = stored.keys.findIndex((k) => k.provider === provider);
434
- }
435
- }
436
- if (index < 0) {
437
- const labelMsg = label ? ` with label "${label}"` : "";
438
- return {
439
- success: false,
440
- error: `No API key found for provider: ${provider}${labelMsg}`
441
- };
442
- }
443
- const removedKey = stored.keys[index];
444
- stored.keys.splice(index, 1);
445
- if (removedKey?.isPrimary) {
446
- const nextKey = stored.keys.find((k) => k.provider === provider);
447
- if (nextKey) {
448
- nextKey.isPrimary = true;
449
- }
450
- }
451
- await this.saveKeys(stored);
452
- return { success: true };
453
- } catch (error) {
454
- return {
455
- success: false,
456
- error: `Failed to remove key: ${error instanceof Error ? error.message : "Unknown error"}`
457
- };
458
- }
459
- }
460
- async setPrimary(provider, label) {
461
- try {
462
- const stored = await this.loadKeys();
463
- const targetKey = stored.keys.find((k) => k.provider === provider && k.label === label);
464
- if (!targetKey) {
465
- return {
466
- success: false,
467
- error: `No key found for ${provider} with label "${label}"`
468
- };
469
- }
470
- for (const key of stored.keys) {
471
- if (key.provider === provider) {
472
- key.isPrimary = key.label === label;
473
- }
474
- }
475
- await this.saveKeys(stored);
476
- return { success: true };
477
- } catch (error) {
478
- return {
479
- success: false,
480
- error: `Failed to set primary: ${error instanceof Error ? error.message : "Unknown error"}`
481
- };
482
- }
483
- }
484
- async listProviders() {
485
- try {
486
- const stored = await this.loadKeys();
487
- const providers = /* @__PURE__ */ new Set();
488
- for (const key of stored.keys) {
489
- providers.add(key.provider);
490
- }
491
- return Array.from(providers);
492
- } catch {
493
- return [];
494
- }
495
- }
496
- async listKeys(provider) {
497
- try {
498
- const stored = await this.loadKeys();
499
- if (provider) {
500
- return stored.keys.filter((k) => k.provider === provider);
501
- }
502
- return stored.keys;
503
- } catch {
504
- return [];
505
- }
506
- }
507
- async hasAnyKey() {
508
- const stored = await this.loadKeys();
509
- return stored.keys.length > 0;
510
- }
511
- async getKeyConfig(provider, label) {
512
- try {
513
- const stored = await this.loadKeys();
514
- if (label) {
515
- return stored.keys.find((k) => k.provider === provider && k.label === label) ?? null;
516
- }
517
- return stored.keys.find((k) => k.provider === provider && k.isPrimary) ?? stored.keys.find((k) => k.provider === provider) ?? null;
518
- } catch {
519
- return null;
520
- }
521
- }
522
- async getAdversarialStatus() {
523
- const providers = await this.listProviders();
524
- const enabled = providers.length >= 2;
525
- if (enabled) {
526
- return {
527
- enabled: true,
528
- providerCount: providers.length,
529
- providers,
530
- message: `Adversarial features enabled (${providers.length} providers: ${providers.join(", ")})`
531
- };
532
- } else if (providers.length === 1) {
533
- return {
534
- enabled: false,
535
- providerCount: 1,
536
- providers,
537
- message: `Adversarial features require keys from 2+ providers. Add another provider to unlock.`
538
- };
539
- } else {
540
- return {
541
- enabled: false,
542
- providerCount: 0,
543
- providers: [],
544
- message: `No API keys configured. Add keys from 2+ providers to enable adversarial features.`
545
- };
546
- }
547
- }
548
- };
549
- var keyManager = new KeyManager();
550
-
551
- // src/core/keys/validator.ts
552
- var KeyValidator = class {
553
- async validateKey(provider, apiKey) {
554
- switch (provider) {
555
- case "anthropic":
556
- return this.validateAnthropicKey(apiKey);
557
- case "openai":
558
- return this.validateOpenAIKey(apiKey);
559
- case "google":
560
- return this.validateGoogleKey(apiKey);
561
- default:
562
- return { valid: false, error: `Unknown provider: ${provider}`, provider };
563
- }
564
- }
565
- async validateAnthropicKey(apiKey) {
566
- try {
567
- const response = await fetch("https://api.anthropic.com/v1/messages", {
568
- method: "POST",
569
- headers: {
570
- "Content-Type": "application/json",
571
- "x-api-key": apiKey,
572
- "anthropic-version": "2023-06-01"
573
- },
574
- body: JSON.stringify({
575
- model: "claude-3-haiku-20240307",
576
- max_tokens: 1,
577
- messages: [{ role: "user", content: "Hi" }]
578
- })
579
- });
580
- if (response.status === 401) {
581
- return {
582
- valid: false,
583
- error: "Invalid API key. Please check your Anthropic API key.",
584
- provider: "anthropic"
585
- };
586
- }
587
- if (response.status === 400) {
588
- const data = await response.json();
589
- if (data.error?.message?.includes("credit")) {
590
- return {
591
- valid: false,
592
- error: "API key valid but no credits. Please add credits to your Anthropic account.",
593
- provider: "anthropic"
594
- };
595
- }
596
- }
597
- if (response.ok || response.status === 429 || response.status === 404) {
598
- return { valid: true, provider: "anthropic" };
599
- }
600
- return {
601
- valid: true,
602
- provider: "anthropic"
603
- };
604
- } catch (error) {
605
- return {
606
- valid: false,
607
- error: `Connection error: ${error instanceof Error ? error.message : "Unknown error"}`,
608
- provider: "anthropic"
609
- };
610
- }
611
- }
612
- async validateOpenAIKey(apiKey) {
613
- try {
614
- const response = await fetch("https://api.openai.com/v1/models", {
615
- method: "GET",
616
- headers: {
617
- Authorization: `Bearer ${apiKey}`
618
- }
619
- });
620
- if (response.status === 401) {
621
- return {
622
- valid: false,
623
- error: "Invalid API key. Please check your OpenAI API key.",
624
- provider: "openai"
625
- };
626
- }
627
- if (response.ok) {
628
- return { valid: true, provider: "openai" };
629
- }
630
- return {
631
- valid: false,
632
- error: `Validation failed with status ${response.status}`,
633
- provider: "openai"
634
- };
635
- } catch (error) {
636
- return {
637
- valid: false,
638
- error: `Connection error: ${error instanceof Error ? error.message : "Unknown error"}`,
639
- provider: "openai"
640
- };
641
- }
642
- }
643
- async validateGoogleKey(apiKey) {
644
- try {
645
- const response = await fetch(
646
- `https://generativelanguage.googleapis.com/v1/models?key=${apiKey}`,
647
- { method: "GET" }
648
- );
649
- if (response.status === 400 || response.status === 401 || response.status === 403) {
650
- return {
651
- valid: false,
652
- error: "Invalid API key. Please check your Google AI API key.",
653
- provider: "google"
654
- };
655
- }
656
- if (response.ok) {
657
- return { valid: true, provider: "google" };
658
- }
659
- return {
660
- valid: false,
661
- error: `Validation failed with status ${response.status}`,
662
- provider: "google"
663
- };
664
- } catch (error) {
665
- return {
666
- valid: false,
667
- error: `Connection error: ${error instanceof Error ? error.message : "Unknown error"}`,
668
- provider: "google"
669
- };
670
- }
671
- }
672
- };
673
-
674
283
  // src/cli/plan.ts
675
284
  var ATOMS_DIR = ".archon/atoms";
676
285
  function createPrompt() {
@@ -692,8 +301,8 @@ async function plan(description, options) {
692
301
  console.log(chalk.yellow('Not authenticated. Run "archon login" first.'));
693
302
  console.log(chalk.dim("For local development, you can continue without authentication."));
694
303
  }
695
- const archPath = join2(process.cwd(), "ARCHITECTURE.md");
696
- if (!existsSync2(archPath)) {
304
+ const archPath = join(process.cwd(), "ARCHITECTURE.md");
305
+ if (!existsSync(archPath)) {
697
306
  console.error(chalk.red('ARCHITECTURE.md not found. Run "archon init" first.'));
698
307
  process.exit(1);
699
308
  }
@@ -724,8 +333,8 @@ Atom created: ${atom.externalId}`));
724
333
  console.log(chalk.dim(`Acceptance Criteria: ${atom.acceptanceCriteria.length} items`));
725
334
  let apiKey = process.env["ANTHROPIC_API_KEY"];
726
335
  if (!apiKey) {
727
- const keyManager2 = new KeyManager();
728
- const storedKey = await keyManager2.getKey("anthropic");
336
+ const keyManager = new KeyManager();
337
+ const storedKey = await keyManager.getKey("anthropic");
729
338
  if (storedKey) {
730
339
  apiKey = storedKey;
731
340
  }
@@ -835,24 +444,24 @@ function displayPlan(plan2) {
835
444
  console.log(chalk.bold("\nComplexity:"), plan2.estimated_complexity);
836
445
  }
837
446
  async function saveAtom(atom) {
838
- const atomsDir = join2(process.cwd(), ATOMS_DIR);
839
- if (!existsSync2(atomsDir)) {
840
- await mkdir2(atomsDir, { recursive: true });
447
+ const atomsDir = join(process.cwd(), ATOMS_DIR);
448
+ if (!existsSync(atomsDir)) {
449
+ await mkdir(atomsDir, { recursive: true });
841
450
  }
842
- const atomFile = join2(atomsDir, `${atom.externalId}.json`);
843
- await writeFile2(atomFile, JSON.stringify(atom, null, 2));
451
+ const atomFile = join(atomsDir, `${atom.externalId}.json`);
452
+ await writeFile(atomFile, JSON.stringify(atom, null, 2));
844
453
  }
845
454
  async function loadAtom(atomId) {
846
- const atomFile = join2(process.cwd(), ATOMS_DIR, `${atomId}.json`);
847
- if (!existsSync2(atomFile)) {
455
+ const atomFile = join(process.cwd(), ATOMS_DIR, `${atomId}.json`);
456
+ if (!existsSync(atomFile)) {
848
457
  return null;
849
458
  }
850
- const content = await readFile2(atomFile, "utf-8");
459
+ const content = await readFile(atomFile, "utf-8");
851
460
  return JSON.parse(content);
852
461
  }
853
462
  async function listLocalAtoms() {
854
- const atomsDir = join2(process.cwd(), ATOMS_DIR);
855
- if (!existsSync2(atomsDir)) {
463
+ const atomsDir = join(process.cwd(), ATOMS_DIR);
464
+ if (!existsSync(atomsDir)) {
856
465
  return [];
857
466
  }
858
467
  const { readdir } = await import("fs/promises");
@@ -870,8 +479,6 @@ async function listLocalAtoms() {
870
479
  }
871
480
 
872
481
  export {
873
- keyManager,
874
- KeyValidator,
875
482
  plan,
876
483
  loadAtom,
877
484
  listLocalAtoms
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadAtom
3
- } from "./chunk-4NZPAEKS.js";
3
+ } from "./chunk-EDP55FCI.js";
4
4
  import {
5
5
  ArchitectureParser
6
6
  } from "./chunk-2CFO5GVH.js";
@@ -0,0 +1,159 @@
1
+ import {
2
+ KeyValidator,
3
+ keyManager
4
+ } from "./chunk-SMR7JQK6.js";
5
+ import {
6
+ loadConfig,
7
+ saveConfig
8
+ } from "./chunk-WCCBJSNI.js";
9
+
10
+ // src/cli/keys.ts
11
+ import chalk from "chalk";
12
+ import ora from "ora";
13
+ import { createInterface } from "readline";
14
+ var VALID_PROVIDERS = ["anthropic", "openai", "google"];
15
+ function isValidProvider(provider) {
16
+ return VALID_PROVIDERS.includes(provider);
17
+ }
18
+ async function promptForKey(provider) {
19
+ const rl = createInterface({
20
+ input: process.stdin,
21
+ output: process.stdout
22
+ });
23
+ return new Promise((resolve) => {
24
+ const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
25
+ rl.question(`Enter your ${providerName} API key: `, (answer) => {
26
+ rl.close();
27
+ resolve(answer.trim());
28
+ });
29
+ });
30
+ }
31
+ async function addKey(provider, options = {}) {
32
+ if (!isValidProvider(provider)) {
33
+ console.error(chalk.red(`Invalid provider: ${provider}`));
34
+ console.log(chalk.dim(`Valid providers: ${VALID_PROVIDERS.join(", ")}`));
35
+ process.exit(1);
36
+ }
37
+ const label = options.label ?? "default";
38
+ const apiKey = await promptForKey(provider);
39
+ if (!apiKey) {
40
+ console.error(chalk.red("API key cannot be empty"));
41
+ process.exit(1);
42
+ }
43
+ const spinner = ora("Validating API key...").start();
44
+ const validator = new KeyValidator();
45
+ const validationResult = await validator.validateKey(provider, apiKey);
46
+ if (!validationResult.valid) {
47
+ spinner.fail(chalk.red(`API key validation failed: ${validationResult.error}`));
48
+ process.exit(1);
49
+ }
50
+ spinner.text = "Encrypting and storing API key...";
51
+ const result = await keyManager.addKey(provider, apiKey, label);
52
+ if (!result.success) {
53
+ spinner.fail(chalk.red(`Failed to store key: ${result.error}`));
54
+ process.exit(1);
55
+ }
56
+ const config = await loadConfig();
57
+ if (config.tier === "FREE") {
58
+ await saveConfig({ ...config, tier: "BYOK" });
59
+ spinner.succeed(chalk.green(`API key for ${provider} (${label}) added successfully!`));
60
+ console.log(chalk.blue("Your tier has been upgraded to BYOK (Bring Your Own Key)"));
61
+ console.log(chalk.dim("You now have access to all models and unlimited atoms."));
62
+ } else {
63
+ spinner.succeed(chalk.green(`API key for ${provider} (${label}) added successfully!`));
64
+ }
65
+ const adversarialStatus = await keyManager.getAdversarialStatus();
66
+ if (adversarialStatus.enabled) {
67
+ console.log(chalk.green(`\u2713 ${adversarialStatus.message}`));
68
+ } else {
69
+ console.log(chalk.yellow(`\u25CB ${adversarialStatus.message}`));
70
+ }
71
+ }
72
+ async function listKeys() {
73
+ const spinner = ora("Loading configured keys...").start();
74
+ const keys = await keyManager.listKeys();
75
+ spinner.stop();
76
+ if (keys.length === 0) {
77
+ console.log(chalk.yellow("No API keys configured"));
78
+ console.log(chalk.dim("Run `archon keys add <provider>` to add a key"));
79
+ console.log(chalk.dim(`Available providers: ${VALID_PROVIDERS.join(", ")}`));
80
+ return;
81
+ }
82
+ console.log(chalk.green("Configured API keys:"));
83
+ console.log();
84
+ const byProvider = {};
85
+ for (const key of keys) {
86
+ if (!byProvider[key.provider]) {
87
+ byProvider[key.provider] = [];
88
+ }
89
+ byProvider[key.provider]?.push(key);
90
+ }
91
+ for (const [provider, providerKeys] of Object.entries(byProvider)) {
92
+ console.log(chalk.blue(` ${provider.toUpperCase()}`));
93
+ for (const key of providerKeys ?? []) {
94
+ const addedDate = new Date(key.createdAt).toLocaleDateString();
95
+ const primaryBadge = key.isPrimary ? chalk.green(" [primary]") : "";
96
+ console.log(` \u2022 ${key.label}${primaryBadge} ${chalk.dim(`(added ${addedDate})`)}`);
97
+ }
98
+ }
99
+ console.log();
100
+ const adversarialStatus = await keyManager.getAdversarialStatus();
101
+ if (adversarialStatus.enabled) {
102
+ console.log(chalk.green(`\u2713 ${adversarialStatus.message}`));
103
+ } else {
104
+ console.log(chalk.yellow(`\u25CB ${adversarialStatus.message}`));
105
+ }
106
+ console.log();
107
+ console.log(chalk.dim("Note: API keys are stored locally with encryption"));
108
+ }
109
+ async function removeKey(provider, options = {}) {
110
+ if (!isValidProvider(provider)) {
111
+ console.error(chalk.red(`Invalid provider: ${provider}`));
112
+ console.log(chalk.dim(`Valid providers: ${VALID_PROVIDERS.join(", ")}`));
113
+ process.exit(1);
114
+ }
115
+ const label = options.label;
116
+ const labelMsg = label ? ` (${label})` : "";
117
+ const spinner = ora(`Removing API key for ${provider}${labelMsg}...`).start();
118
+ const result = await keyManager.removeKey(provider, label);
119
+ if (!result.success) {
120
+ spinner.fail(chalk.red(result.error ?? "Failed to remove key"));
121
+ process.exit(1);
122
+ }
123
+ const hasRemainingKeys = await keyManager.hasAnyKey();
124
+ if (!hasRemainingKeys) {
125
+ const config = await loadConfig();
126
+ if (config.tier === "BYOK") {
127
+ await saveConfig({ ...config, tier: "FREE" });
128
+ spinner.succeed(chalk.green(`API key for ${provider}${labelMsg} removed`));
129
+ console.log(chalk.yellow("No API keys remaining. Tier reverted to FREE."));
130
+ return;
131
+ }
132
+ }
133
+ spinner.succeed(chalk.green(`API key for ${provider}${labelMsg} removed`));
134
+ const adversarialStatus = await keyManager.getAdversarialStatus();
135
+ if (!adversarialStatus.enabled && adversarialStatus.providerCount > 0) {
136
+ console.log(chalk.yellow(`\u25CB ${adversarialStatus.message}`));
137
+ }
138
+ }
139
+ async function setPrimaryKey(provider, label) {
140
+ if (!isValidProvider(provider)) {
141
+ console.error(chalk.red(`Invalid provider: ${provider}`));
142
+ console.log(chalk.dim(`Valid providers: ${VALID_PROVIDERS.join(", ")}`));
143
+ process.exit(1);
144
+ }
145
+ const spinner = ora(`Setting primary key for ${provider} to "${label}"...`).start();
146
+ const result = await keyManager.setPrimary(provider, label);
147
+ if (!result.success) {
148
+ spinner.fail(chalk.red(result.error ?? "Failed to set primary key"));
149
+ process.exit(1);
150
+ }
151
+ spinner.succeed(chalk.green(`Primary key for ${provider} set to "${label}"`));
152
+ }
153
+
154
+ export {
155
+ addKey,
156
+ listKeys,
157
+ removeKey,
158
+ setPrimaryKey
159
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listLocalAtoms
3
- } from "./chunk-4NZPAEKS.js";
3
+ } from "./chunk-EDP55FCI.js";
4
4
 
5
5
  // src/cli/list.ts
6
6
  import chalk from "chalk";