apex-dev 3.10.23 → 3.10.25

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/dist/index.js +211 -81
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -305,6 +305,90 @@ var require_config = __commonJS((exports, module) => {
305
305
  const OpenAI = __require("openai");
306
306
  const fs = __require("fs");
307
307
  const path = __require("path");
308
+ const os = __require("os");
309
+ const CONFIG_PATH = path.join(os.homedir(), ".apex-dev", "config.json");
310
+ function readSavedApiKeys() {
311
+ try {
312
+ if (!fs.existsSync(CONFIG_PATH))
313
+ return {};
314
+ const parsed = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
315
+ return parsed && typeof parsed === "object" ? parsed : {};
316
+ } catch {
317
+ return {};
318
+ }
319
+ }
320
+ function writeSavedApiKeys(config) {
321
+ const dir = path.dirname(CONFIG_PATH);
322
+ if (!fs.existsSync(dir)) {
323
+ fs.mkdirSync(dir, { recursive: true });
324
+ }
325
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
326
+ fs.chmodSync(CONFIG_PATH, 384);
327
+ }
328
+ function getSavedApiKey(providerKey) {
329
+ const config = readSavedApiKeys();
330
+ return config[providerKey] || "";
331
+ }
332
+ function getProviderLoginState(providerKey) {
333
+ const provider = PROVIDERS[providerKey];
334
+ if (!provider)
335
+ return "empty";
336
+ if (process.env[provider.envKey])
337
+ return "logged-in";
338
+ if (getSavedApiKey(providerKey))
339
+ return "saved";
340
+ return "empty";
341
+ }
342
+ function updateSavedApiKey(providerKey, apiKey) {
343
+ const config = readSavedApiKeys();
344
+ if (apiKey) {
345
+ config[providerKey] = apiKey;
346
+ } else {
347
+ delete config[providerKey];
348
+ }
349
+ if (Object.keys(config).length === 0) {
350
+ try {
351
+ fs.unlinkSync(CONFIG_PATH);
352
+ } catch {}
353
+ return config;
354
+ }
355
+ writeSavedApiKeys(config);
356
+ return config;
357
+ }
358
+ function clearSavedApiKey(providerKey) {
359
+ return updateSavedApiKey(providerKey, "");
360
+ }
361
+ function loginProvider(providerKey, apiKey) {
362
+ updateSavedApiKey(providerKey, apiKey);
363
+ setProvider(providerKey, apiKey);
364
+ return { providerKey, apiKey };
365
+ }
366
+ function logoutProvider(providerKey) {
367
+ clearSavedApiKey(providerKey);
368
+ const provider = PROVIDERS[providerKey];
369
+ if (provider) {
370
+ delete process.env[provider.envKey];
371
+ if (currentProvider === providerKey) {
372
+ setProvider(providerKey, "");
373
+ }
374
+ }
375
+ const remaining = getFirstSavedProvider();
376
+ if (remaining) {
377
+ currentProvider = remaining.providerKey;
378
+ process.env[remaining.provider.envKey] = remaining.apiKey;
379
+ setProvider(remaining.providerKey, remaining.apiKey);
380
+ }
381
+ return remaining;
382
+ }
383
+ function getFirstSavedProvider() {
384
+ const config = readSavedApiKeys();
385
+ for (const [providerKey, provider] of Object.entries(PROVIDERS)) {
386
+ if (config[providerKey]) {
387
+ return { providerKey, apiKey: config[providerKey], provider };
388
+ }
389
+ }
390
+ return null;
391
+ }
308
392
  const PROVIDERS = {
309
393
  fireworks: {
310
394
  label: "Fireworks AI",
@@ -413,6 +497,16 @@ var require_config = __commonJS((exports, module) => {
413
497
  return "fireworks";
414
498
  }
415
499
  let currentProvider = detectInitialProvider();
500
+ try {
501
+ const hasEnvKey = Object.values(PROVIDERS).some((p) => process.env[p.envKey]);
502
+ if (!hasEnvKey) {
503
+ const saved = getFirstSavedProvider();
504
+ if (saved) {
505
+ currentProvider = saved.providerKey;
506
+ process.env[saved.provider.envKey] = saved.apiKey;
507
+ }
508
+ }
509
+ } catch {}
416
510
  const currentModels = Object.assign({}, PROVIDERS[currentProvider].models);
417
511
  const MAX_TOOL_ITERATIONS = 50;
418
512
  const MAX_OUTPUT_LEN = 12000;
@@ -453,7 +547,7 @@ var require_config = __commonJS((exports, module) => {
453
547
 
454
548
  - **Idiomatic Changes:** When editing, understand the local context (imports, functions/classes) to ensure your changes integrate naturally and idiomatically.
455
549
 
456
- - **Simplicity & Minimalism:** You should make as few changes as possible to the codebase to address the user's request. Only do what the user has asked for and no more. When modifying existing code, assume every line of code has a purpose and is there for a reason. Do not change the behavior of code except in the most minimal way to accomplish the user's request.
550
+ - **Simplicity & Minimalism:** You should make as few changes as possible to the codebase to address the user's request. Only do what the user has asked and no more. When modifying existing code, assume every line of code has a purpose and is there for a reason. Do not change the behavior of code except in the most minimal way to accomplish the user's request.
457
551
 
458
552
  - **Code Reuse:** Always reuse helper functions, components, classes, etc., whenever possible! Don't reimplement what already exists elsewhere in the codebase.
459
553
 
@@ -489,7 +583,7 @@ var require_config = __commonJS((exports, module) => {
489
583
 
490
584
  Use the spawn_agents tool to spawn specialized agents to help you complete the user's request.
491
585
 
492
- - **Spawn multiple agents in parallel:** This increases the speed of your response **and** allows you to be more comprehensive by spawning more total agents to synthesize the best response.
586
+ - **Spawn multiple agents in parallel:** This increases the speed of your response **and** allows you to be more comprehensive by spawning more total agents to synthesize the best solution.
493
587
 
494
588
  - **Sequence agents properly:** Keep in mind dependencies when spawning different agents. Don't spawn agents in parallel that depend on each other.
495
589
 
@@ -869,25 +963,6 @@ The user asks you to implement a new feature. You respond in multiple steps:
869
963
  deepseek: { model: "deepseek/deepseek-chat-v3", temperature: 0.1, maxTokens: 8192 },
870
964
  minimax: { model: "minimax/minimax-01", temperature: 0.1, maxTokens: 8192 }
871
965
  };
872
- const os = __require("os");
873
- let savedProvider = null;
874
- try {
875
- const configPath = path.join(os.homedir(), ".apex-dev", "config.json");
876
- if (fs.existsSync(configPath)) {
877
- const savedConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
878
- const hasEnvKey = Object.values(PROVIDERS).some((p) => process.env[p.envKey]);
879
- if (!hasEnvKey) {
880
- for (const [providerKey, provider] of Object.entries(PROVIDERS)) {
881
- if (savedConfig[providerKey]) {
882
- currentProvider = providerKey;
883
- process.env[provider.envKey] = savedConfig[providerKey];
884
- savedProvider = providerKey;
885
- break;
886
- }
887
- }
888
- }
889
- }
890
- } catch (e) {}
891
966
  const _initialProvider = PROVIDERS[currentProvider];
892
967
  const _initialKey = process.env[_initialProvider.envKey] || "no-key";
893
968
  let _internalClient = new OpenAI({
@@ -1016,6 +1091,15 @@ The user asks you to implement a new feature. You respond in multiple steps:
1016
1091
  },
1017
1092
  detectInitialProvider,
1018
1093
  setProvider,
1094
+ readSavedApiKeys,
1095
+ writeSavedApiKeys,
1096
+ getSavedApiKey,
1097
+ getProviderLoginState,
1098
+ updateSavedApiKey,
1099
+ clearSavedApiKey,
1100
+ loginProvider,
1101
+ logoutProvider,
1102
+ getFirstSavedProvider,
1019
1103
  agentConfigs,
1020
1104
  agentModes,
1021
1105
  codeEditorModelVariants,
@@ -3301,7 +3385,7 @@ var require_commands = __commonJS((exports, module2) => {
3301
3385
  var fs2 = __require2("fs");
3302
3386
  var path2 = __require2("path");
3303
3387
  var { execSync } = __require2("child_process");
3304
- var { PROJECT_ROOT, session, resolvePath } = require_config();
3388
+ var { PROJECT_ROOT, session, resolvePath, logoutProvider, getProviderLoginState } = require_config();
3305
3389
  var { executeTool } = require_toolExecutors();
3306
3390
  var store = require_store();
3307
3391
  async function handleSlashCommand(input) {
@@ -3311,6 +3395,20 @@ var require_commands = __commonJS((exports, module2) => {
3311
3395
  case "/help":
3312
3396
  store.setState({ showHelp: true });
3313
3397
  break;
3398
+ case "/login":
3399
+ case "/provider":
3400
+ store.setState({ showHelp: false, needsConfig: true });
3401
+ break;
3402
+ case "/logout": {
3403
+ const provider = store.getSnapshot().provider;
3404
+ if (getProviderLoginState(provider) === "logged-in") {
3405
+ logoutProvider(provider);
3406
+ store.setState({ showHelp: false, needsConfig: true, apiKey: "" });
3407
+ } else {
3408
+ store.setState({ showHelp: false, needsConfig: true });
3409
+ }
3410
+ break;
3411
+ }
3314
3412
  case "/clear":
3315
3413
  session.conversationHistory = [];
3316
3414
  store.clearMessages();
@@ -4376,37 +4474,63 @@ function ProviderSelector() {
4376
4474
  var providers = import_config.PROVIDERS;
4377
4475
  var providerKey = PROVIDER_ORDER[focusedIdx];
4378
4476
  var provider = providers[providerKey];
4477
+ function getStoredKey(key) {
4478
+ return import_config.getSavedApiKey(key);
4479
+ }
4480
+ function loginState(key) {
4481
+ return import_config.getProviderLoginState(key);
4482
+ }
4379
4483
  function isConfigured(key) {
4380
- var envKey = providers[key].envKey;
4381
- var hasEnv = Boolean(process.env[envKey]);
4382
- var hasStored = key === state.provider && Boolean(state.apiKey);
4383
- return hasEnv || hasStored;
4484
+ return loginState(key) !== "empty";
4384
4485
  }
4385
- function isDefault(key) {
4386
- return key === state.provider && Boolean(state.apiKey);
4486
+ function isLoggedIn(key) {
4487
+ return loginState(key) === "logged-in";
4387
4488
  }
4388
- function handleSelect() {
4389
- if (isConfigured(providerKey)) {
4390
- var key = process.env[provider.envKey] || state.apiKey;
4391
- import_config.setProvider(providerKey, key);
4392
- import_store.setState({
4393
- apiKey: key,
4394
- provider: providerKey,
4395
- needsConfig: false
4396
- });
4397
- return;
4398
- }
4399
- setStep("key");
4489
+ function finishLogin(providerKey2, key) {
4490
+ import_config.loginProvider(providerKey2, key);
4491
+ import_store.setState({
4492
+ apiKey: key,
4493
+ provider: providerKey2,
4494
+ needsConfig: false
4495
+ });
4400
4496
  }
4401
- function handleSubmitKey() {
4497
+ function handleLogin() {
4402
4498
  var key = input.trim();
4403
4499
  if (!key)
4404
4500
  return;
4405
- import_config.setProvider(providerKey, key);
4406
- import_store.setState({ apiKey: key, provider: providerKey, needsConfig: false });
4501
+ finishLogin(providerKey, key);
4407
4502
  setInput("");
4408
4503
  setStep("select");
4409
4504
  }
4505
+ function handleLogout() {
4506
+ var remaining = import_config.logoutProvider(providerKey);
4507
+ if (remaining) {
4508
+ import_store.setState({
4509
+ apiKey: remaining.apiKey,
4510
+ provider: remaining.providerKey,
4511
+ needsConfig: false
4512
+ });
4513
+ } else {
4514
+ import_store.setState({
4515
+ apiKey: "",
4516
+ provider: providerKey,
4517
+ needsConfig: true
4518
+ });
4519
+ }
4520
+ setInput("");
4521
+ setStep("select");
4522
+ }
4523
+ function handleSelect() {
4524
+ if (isLoggedIn(providerKey)) {
4525
+ handleLogout();
4526
+ return;
4527
+ }
4528
+ if (isConfigured(providerKey)) {
4529
+ finishLogin(providerKey, getStoredKey(providerKey));
4530
+ return;
4531
+ }
4532
+ setStep("key");
4533
+ }
4410
4534
  var handleKeyPress = function(key) {
4411
4535
  if (step === "select") {
4412
4536
  if (key.name === "up" || key.name === "k") {
@@ -4419,16 +4543,20 @@ function ProviderSelector() {
4419
4543
  });
4420
4544
  } else if (key.name === "return" || key.name === "enter") {
4421
4545
  handleSelect();
4546
+ } else if (key.name === "l") {
4547
+ if (isLoggedIn(providerKey))
4548
+ handleLogout();
4422
4549
  }
4423
4550
  } else {
4424
4551
  if (key.name === "escape") {
4425
4552
  setStep("select");
4426
4553
  setInput("");
4427
4554
  } else if (key.name === "return" || key.name === "enter") {
4428
- handleSubmitKey();
4555
+ handleLogin();
4429
4556
  }
4430
4557
  }
4431
4558
  };
4559
+ var selectedState = loginState(providerKey);
4432
4560
  return jsx_runtime.jsx("box", {
4433
4561
  style: {
4434
4562
  flexDirection: "column",
@@ -4451,15 +4579,14 @@ function ProviderSelector() {
4451
4579
  style: { paddingLeft: 4, paddingRight: 4, marginBottom: 1 },
4452
4580
  children: jsx_runtime.jsx("text", {
4453
4581
  fg: import_theme.colors.dim,
4454
- children: "Use \u2191\u2193 or j/k to navigate, Enter to continue, or select a configured provider to reuse its key."
4582
+ children: "Use \u2191\u2193 or j/k to navigate. Enter logs in or out depending on the selected provider's state."
4455
4583
  })
4456
4584
  }),
4457
4585
  PROVIDER_ORDER.map(function(key, idx) {
4458
4586
  var focused = idx === focusedIdx;
4459
- var configured = isConfigured(key);
4460
- var def = isDefault(key);
4461
- var statusFg = def ? import_theme.colors.accent : configured ? import_theme.colors.green : import_theme.colors.dim;
4462
- var statusText = def ? "Active" : configured ? "Configured" : "Needs key";
4587
+ var stateLabel = loginState(key);
4588
+ var statusFg = stateLabel === "logged-in" ? import_theme.colors.green : stateLabel === "saved" ? import_theme.colors.yellow : import_theme.colors.dim;
4589
+ var statusText = stateLabel === "logged-in" ? "Logged in" : stateLabel === "saved" ? "Logged out" : "Needs key";
4463
4590
  return jsx_runtime.jsxs("box", {
4464
4591
  style: {
4465
4592
  flexDirection: "row",
@@ -4471,7 +4598,13 @@ function ProviderSelector() {
4471
4598
  },
4472
4599
  onMouseDown: function() {
4473
4600
  setFocusedIdx(idx);
4474
- handleSelect();
4601
+ if (stateLabel === "logged-in") {
4602
+ handleLogout();
4603
+ } else if (stateLabel === "saved") {
4604
+ finishLogin(key, getStoredKey(key));
4605
+ } else {
4606
+ setStep("key");
4607
+ }
4475
4608
  },
4476
4609
  children: [
4477
4610
  jsx_runtime.jsx("text", {
@@ -4499,7 +4632,7 @@ function ProviderSelector() {
4499
4632
  style: { paddingLeft: 4, paddingRight: 4, marginTop: 2 },
4500
4633
  children: jsx_runtime.jsx("text", {
4501
4634
  fg: import_theme.colors.dim,
4502
- children: "Keys are stored in ~/.apex-dev/config.json or can be supplied via environment variables."
4635
+ children: selectedState === "logged-in" ? "Press Enter to log out of the selected provider." : selectedState === "saved" ? "Press Enter to log in with the saved key." : "Press Enter to log in with a new key. Keys are stored in ~/.apex-dev/config.json or can be supplied via environment variables."
4503
4636
  })
4504
4637
  })
4505
4638
  ]
@@ -4544,7 +4677,7 @@ function ProviderSelector() {
4544
4677
  focused: true,
4545
4678
  value: input,
4546
4679
  onChange: setInput,
4547
- onSubmit: handleSubmitKey,
4680
+ onSubmit: handleLogin,
4548
4681
  placeholder: "Paste your API key here...",
4549
4682
  fg: import_theme.colors.text
4550
4683
  })
@@ -4554,7 +4687,7 @@ function ProviderSelector() {
4554
4687
  style: { paddingLeft: 4, paddingRight: 4 },
4555
4688
  children: jsx_runtime.jsx("text", {
4556
4689
  fg: import_theme.colors.dim,
4557
- children: "Press Enter to confirm"
4690
+ children: "Press Enter to login"
4558
4691
  })
4559
4692
  })
4560
4693
  ]
@@ -4753,37 +4886,34 @@ function App() {
4753
4886
  });
4754
4887
  }
4755
4888
  }, []);
4756
- const forceSetup = process.env.APEX_DEV_NEEDS_CONFIG === "true";
4757
- const shouldShowSetup = forceSetup || state.needsConfig;
4758
- if (shouldShowSetup) {
4759
- return /* @__PURE__ */ jsx_runtime15.jsx("box", {
4760
- style: { flexDirection: "column", flexGrow: 1 },
4761
- children: /* @__PURE__ */ jsx_runtime15.jsx(globalThis._ProviderSelector, {})
4762
- });
4763
- }
4889
+ const shouldShowSetup = process.env.APEX_DEV_NEEDS_CONFIG === "true" || state.needsConfig;
4764
4890
  return /* @__PURE__ */ jsx_runtime15.jsxs("box", {
4765
4891
  style: { flexDirection: "column", flexGrow: 1 },
4766
4892
  children: [
4767
- /* @__PURE__ */ jsx_runtime15.jsx(Header, {}),
4768
- /* @__PURE__ */ jsx_runtime15.jsx(Divider, {}),
4769
- /* @__PURE__ */ jsx_runtime15.jsx(ChatArea, {
4770
- messages: state.messages,
4771
- streamingContent: state.streamingContent,
4772
- streamingThinking: state.streamingThinking,
4773
- isProcessing: state.isProcessing
4774
- }),
4775
- /* @__PURE__ */ jsx_runtime15.jsx(Divider, {}),
4776
- /* @__PURE__ */ jsx_runtime15.jsx(StatusBar, {
4777
- isProcessing: state.isProcessing
4778
- }),
4779
- /* @__PURE__ */ jsx_runtime15.jsx(InputBar, {
4780
- disabled: state.isProcessing || state.showHelp,
4781
- onSubmit: handleInput
4782
- }),
4783
- state.showHelp ? /* @__PURE__ */ jsx_runtime15.jsx(HelpModal, {
4784
- onClose: () => import_store5.setState({ showHelp: false }),
4785
- onCommand: handleHelpCommand
4786
- }) : null
4893
+ shouldShowSetup ? /* @__PURE__ */ jsx_runtime15.jsx(globalThis._ProviderSelector, {}) : /* @__PURE__ */ jsx_runtime15.jsxs(jsx_runtime15.Fragment, {
4894
+ children: [
4895
+ /* @__PURE__ */ jsx_runtime15.jsx(Header, {}),
4896
+ /* @__PURE__ */ jsx_runtime15.jsx(Divider, {}),
4897
+ /* @__PURE__ */ jsx_runtime15.jsx(ChatArea, {
4898
+ messages: state.messages,
4899
+ streamingContent: state.streamingContent,
4900
+ streamingThinking: state.streamingThinking,
4901
+ isProcessing: state.isProcessing
4902
+ }),
4903
+ /* @__PURE__ */ jsx_runtime15.jsx(Divider, {}),
4904
+ /* @__PURE__ */ jsx_runtime15.jsx(StatusBar, {
4905
+ isProcessing: state.isProcessing
4906
+ }),
4907
+ /* @__PURE__ */ jsx_runtime15.jsx(InputBar, {
4908
+ disabled: state.isProcessing || state.showHelp || shouldShowSetup,
4909
+ onSubmit: handleInput
4910
+ }),
4911
+ state.showHelp ? /* @__PURE__ */ jsx_runtime15.jsx(HelpModal, {
4912
+ onClose: () => import_store5.setState({ showHelp: false }),
4913
+ onCommand: handleHelpCommand
4914
+ }) : null
4915
+ ]
4916
+ })
4787
4917
  ]
4788
4918
  });
4789
4919
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apex-dev",
3
- "version": "3.10.23",
3
+ "version": "3.10.25",
4
4
  "description": "Apex AI - a friendly agentic coding assistant for the terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {