apex-dev 3.10.21 → 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.
- package/cli.js +121 -13
- package/dist/apex-dev +45094 -41465
- package/dist/index.js +312 -121
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -104,6 +104,7 @@ var require_store = __commonJS((exports, module2) => {
|
|
|
104
104
|
messages: state.messages.map((m2) => m2.id === id ? { ...m2, ...updates } : m2)
|
|
105
105
|
};
|
|
106
106
|
notify();
|
|
107
|
+
return id;
|
|
107
108
|
}
|
|
108
109
|
function toggleMessageExpanded(id) {
|
|
109
110
|
state = {
|
|
@@ -304,6 +305,90 @@ var require_config = __commonJS((exports, module) => {
|
|
|
304
305
|
const OpenAI = __require("openai");
|
|
305
306
|
const fs = __require("fs");
|
|
306
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
|
+
}
|
|
307
392
|
const PROVIDERS = {
|
|
308
393
|
fireworks: {
|
|
309
394
|
label: "Fireworks AI",
|
|
@@ -412,6 +497,16 @@ var require_config = __commonJS((exports, module) => {
|
|
|
412
497
|
return "fireworks";
|
|
413
498
|
}
|
|
414
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 {}
|
|
415
510
|
const currentModels = Object.assign({}, PROVIDERS[currentProvider].models);
|
|
416
511
|
const MAX_TOOL_ITERATIONS = 50;
|
|
417
512
|
const MAX_OUTPUT_LEN = 12000;
|
|
@@ -452,7 +547,7 @@ var require_config = __commonJS((exports, module) => {
|
|
|
452
547
|
|
|
453
548
|
- **Idiomatic Changes:** When editing, understand the local context (imports, functions/classes) to ensure your changes integrate naturally and idiomatically.
|
|
454
549
|
|
|
455
|
-
- **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
|
|
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.
|
|
456
551
|
|
|
457
552
|
- **Code Reuse:** Always reuse helper functions, components, classes, etc., whenever possible! Don't reimplement what already exists elsewhere in the codebase.
|
|
458
553
|
|
|
@@ -488,7 +583,7 @@ var require_config = __commonJS((exports, module) => {
|
|
|
488
583
|
|
|
489
584
|
Use the spawn_agents tool to spawn specialized agents to help you complete the user's request.
|
|
490
585
|
|
|
491
|
-
- **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
|
|
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.
|
|
492
587
|
|
|
493
588
|
- **Sequence agents properly:** Keep in mind dependencies when spawning different agents. Don't spawn agents in parallel that depend on each other.
|
|
494
589
|
|
|
@@ -868,25 +963,6 @@ The user asks you to implement a new feature. You respond in multiple steps:
|
|
|
868
963
|
deepseek: { model: "deepseek/deepseek-chat-v3", temperature: 0.1, maxTokens: 8192 },
|
|
869
964
|
minimax: { model: "minimax/minimax-01", temperature: 0.1, maxTokens: 8192 }
|
|
870
965
|
};
|
|
871
|
-
const os = __require("os");
|
|
872
|
-
let savedProvider = null;
|
|
873
|
-
try {
|
|
874
|
-
const configPath = path.join(os.homedir(), ".apex-dev", "config.json");
|
|
875
|
-
if (fs.existsSync(configPath)) {
|
|
876
|
-
const savedConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
877
|
-
const hasEnvKey = Object.values(PROVIDERS).some((p) => process.env[p.envKey]);
|
|
878
|
-
if (!hasEnvKey) {
|
|
879
|
-
for (const [providerKey, provider] of Object.entries(PROVIDERS)) {
|
|
880
|
-
if (savedConfig[providerKey]) {
|
|
881
|
-
currentProvider = providerKey;
|
|
882
|
-
process.env[provider.envKey] = savedConfig[providerKey];
|
|
883
|
-
savedProvider = providerKey;
|
|
884
|
-
break;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
} catch (e) {}
|
|
890
966
|
const _initialProvider = PROVIDERS[currentProvider];
|
|
891
967
|
const _initialKey = process.env[_initialProvider.envKey] || "no-key";
|
|
892
968
|
let _internalClient = new OpenAI({
|
|
@@ -1015,6 +1091,15 @@ The user asks you to implement a new feature. You respond in multiple steps:
|
|
|
1015
1091
|
},
|
|
1016
1092
|
detectInitialProvider,
|
|
1017
1093
|
setProvider,
|
|
1094
|
+
readSavedApiKeys,
|
|
1095
|
+
writeSavedApiKeys,
|
|
1096
|
+
getSavedApiKey,
|
|
1097
|
+
getProviderLoginState,
|
|
1098
|
+
updateSavedApiKey,
|
|
1099
|
+
clearSavedApiKey,
|
|
1100
|
+
loginProvider,
|
|
1101
|
+
logoutProvider,
|
|
1102
|
+
getFirstSavedProvider,
|
|
1018
1103
|
agentConfigs,
|
|
1019
1104
|
agentModes,
|
|
1020
1105
|
codeEditorModelVariants,
|
|
@@ -3300,7 +3385,7 @@ var require_commands = __commonJS((exports, module2) => {
|
|
|
3300
3385
|
var fs2 = __require2("fs");
|
|
3301
3386
|
var path2 = __require2("path");
|
|
3302
3387
|
var { execSync } = __require2("child_process");
|
|
3303
|
-
var { PROJECT_ROOT, session, resolvePath } = require_config();
|
|
3388
|
+
var { PROJECT_ROOT, session, resolvePath, logoutProvider, getProviderLoginState } = require_config();
|
|
3304
3389
|
var { executeTool } = require_toolExecutors();
|
|
3305
3390
|
var store = require_store();
|
|
3306
3391
|
async function handleSlashCommand(input) {
|
|
@@ -3310,6 +3395,20 @@ var require_commands = __commonJS((exports, module2) => {
|
|
|
3310
3395
|
case "/help":
|
|
3311
3396
|
store.setState({ showHelp: true });
|
|
3312
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
|
+
}
|
|
3313
3412
|
case "/clear":
|
|
3314
3413
|
session.conversationHistory = [];
|
|
3315
3414
|
store.clearMessages();
|
|
@@ -3437,13 +3536,15 @@ function Header() {
|
|
|
3437
3536
|
setBranch(b2);
|
|
3438
3537
|
} catch {}
|
|
3439
3538
|
}, []);
|
|
3440
|
-
const
|
|
3539
|
+
const snapshot = import_store_h.getSnapshot();
|
|
3540
|
+
const provider = snapshot.provider;
|
|
3441
3541
|
const providerLabel = import_config.PROVIDERS[provider]?.label || provider;
|
|
3542
|
+
const configReady = !snapshot.needsConfig;
|
|
3442
3543
|
return /* @__PURE__ */ jsx_runtime.jsxs("box", {
|
|
3443
|
-
style: { flexDirection: "row", paddingLeft: 1, paddingRight: 1 },
|
|
3544
|
+
style: { flexDirection: "row", paddingLeft: 1, paddingRight: 1, paddingTop: 1, paddingBottom: 0 },
|
|
3444
3545
|
children: [
|
|
3445
3546
|
/* @__PURE__ */ jsx_runtime.jsx("box", {
|
|
3446
|
-
style: { flexGrow: 1 },
|
|
3547
|
+
style: { flexGrow: 1, flexDirection: "column" },
|
|
3447
3548
|
children: /* @__PURE__ */ jsx_runtime.jsxs("text", {
|
|
3448
3549
|
children: [
|
|
3449
3550
|
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
@@ -3482,15 +3583,36 @@ function Header() {
|
|
|
3482
3583
|
]
|
|
3483
3584
|
})
|
|
3484
3585
|
}),
|
|
3485
|
-
!isNarrow ? /* @__PURE__ */ jsx_runtime.jsxs("
|
|
3586
|
+
!isNarrow ? /* @__PURE__ */ jsx_runtime.jsxs("box", {
|
|
3587
|
+
style: { flexDirection: "column", alignItems: "flex-end" },
|
|
3486
3588
|
children: [
|
|
3487
|
-
/* @__PURE__ */ jsx_runtime.
|
|
3488
|
-
|
|
3489
|
-
|
|
3589
|
+
/* @__PURE__ */ jsx_runtime.jsxs("text", {
|
|
3590
|
+
children: [
|
|
3591
|
+
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
3592
|
+
fg: configReady ? import_theme.colors.green : import_theme.colors.yellow,
|
|
3593
|
+
children: configReady ? "\u25CF" : "\u25CB"
|
|
3594
|
+
}),
|
|
3595
|
+
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
3596
|
+
fg: import_theme.colors.dim,
|
|
3597
|
+
children: " "
|
|
3598
|
+
}),
|
|
3599
|
+
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
3600
|
+
fg: import_theme.colors.muted,
|
|
3601
|
+
children: configReady ? "ready" : "needs setup"
|
|
3602
|
+
})
|
|
3603
|
+
]
|
|
3490
3604
|
}),
|
|
3491
|
-
/* @__PURE__ */ jsx_runtime.
|
|
3492
|
-
|
|
3493
|
-
|
|
3605
|
+
/* @__PURE__ */ jsx_runtime.jsxs("text", {
|
|
3606
|
+
children: [
|
|
3607
|
+
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
3608
|
+
fg: import_theme.colors.dim,
|
|
3609
|
+
children: "provider "
|
|
3610
|
+
}),
|
|
3611
|
+
/* @__PURE__ */ jsx_runtime.jsx("span", {
|
|
3612
|
+
fg: import_theme.colors.primary,
|
|
3613
|
+
children: providerLabel
|
|
3614
|
+
})
|
|
3615
|
+
]
|
|
3494
3616
|
})
|
|
3495
3617
|
]
|
|
3496
3618
|
}) : null
|
|
@@ -3513,7 +3635,7 @@ var jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
|
3513
3635
|
function Welcome() {
|
|
3514
3636
|
const { isNarrow } = useLayout();
|
|
3515
3637
|
return /* @__PURE__ */ jsx_runtime3.jsxs("box", {
|
|
3516
|
-
style: { flexDirection: "column", paddingLeft: 1, marginTop: 1 },
|
|
3638
|
+
style: { flexDirection: "column", paddingLeft: 1, marginTop: 1, marginBottom: 1 },
|
|
3517
3639
|
children: [
|
|
3518
3640
|
/* @__PURE__ */ jsx_runtime3.jsx("text", {
|
|
3519
3641
|
fg: import_theme3.colors.white,
|
|
@@ -3522,8 +3644,13 @@ function Welcome() {
|
|
|
3522
3644
|
}),
|
|
3523
3645
|
/* @__PURE__ */ jsx_runtime3.jsx("text", {
|
|
3524
3646
|
fg: import_theme3.colors.dim,
|
|
3525
|
-
content: isNarrow ? `
|
|
3526
|
-
})
|
|
3647
|
+
content: isNarrow ? `Type a message or /help` : `Apex can read, edit, run commands, and review your code. Use /help to see shortcuts.`
|
|
3648
|
+
}),
|
|
3649
|
+
!isNarrow ? /* @__PURE__ */ jsx_runtime3.jsx("text", {
|
|
3650
|
+
fg: import_theme3.colors.dim,
|
|
3651
|
+
style: { marginTop: 0 },
|
|
3652
|
+
content: `Shortcuts \xB7 /help \xB7 /files \xB7 /diff \xB7 /cost \xB7 /quit \xB7 Max ${import_config2.MAX_TOOL_ITERATIONS} iterations`
|
|
3653
|
+
}) : null
|
|
3527
3654
|
]
|
|
3528
3655
|
});
|
|
3529
3656
|
}
|
|
@@ -4051,16 +4178,18 @@ function InputBar({ disabled, onSubmit }) {
|
|
|
4051
4178
|
inputRef.current.value = "";
|
|
4052
4179
|
onSubmit(trimmed);
|
|
4053
4180
|
};
|
|
4054
|
-
const hint = isNarrow ? "
|
|
4181
|
+
const hint = isNarrow ? "Ctrl+C \xB7 /" : "Ctrl+C exit \xB7 /help \xB7 /files";
|
|
4182
|
+
const placeholder = disabled ? "setup in progress..." : isNarrow ? "Message or /cmd" : "Ask Apex anything, or use /commands";
|
|
4055
4183
|
return /* @__PURE__ */ jsx_runtime12.jsx("box", {
|
|
4056
|
-
style: { flexDirection: "column" },
|
|
4184
|
+
style: { flexDirection: "column", paddingLeft: 1, paddingRight: 1, paddingBottom: 1 },
|
|
4057
4185
|
children: /* @__PURE__ */ jsx_runtime12.jsxs("box", {
|
|
4058
4186
|
style: {
|
|
4059
4187
|
flexDirection: "row",
|
|
4060
4188
|
paddingLeft: 1,
|
|
4061
4189
|
paddingRight: 1,
|
|
4062
4190
|
borderStyle: "rounded",
|
|
4063
|
-
borderColor: disabled ? import_theme12.colors.dim : import_theme12.colors.border
|
|
4191
|
+
borderColor: disabled ? import_theme12.colors.dim : import_theme12.colors.border,
|
|
4192
|
+
backgroundColor: disabled ? import_theme12.colors.surface : undefined
|
|
4064
4193
|
},
|
|
4065
4194
|
children: [
|
|
4066
4195
|
/* @__PURE__ */ jsx_runtime12.jsx("text", {
|
|
@@ -4071,7 +4200,7 @@ function InputBar({ disabled, onSubmit }) {
|
|
|
4071
4200
|
/* @__PURE__ */ jsx_runtime12.jsx("input", {
|
|
4072
4201
|
ref: inputRef,
|
|
4073
4202
|
focused: !disabled,
|
|
4074
|
-
placeholder
|
|
4203
|
+
placeholder,
|
|
4075
4204
|
onSubmit: handleSubmit,
|
|
4076
4205
|
fg: import_theme12.colors.text,
|
|
4077
4206
|
style: { flexGrow: 1 }
|
|
@@ -4087,10 +4216,13 @@ function InputBar({ disabled, onSubmit }) {
|
|
|
4087
4216
|
var import_react_sb = __toESM(require_react(), 1);
|
|
4088
4217
|
var import_theme13 = __toESM(require_theme(), 1);
|
|
4089
4218
|
var import_config3 = __toESM(require_config(), 1);
|
|
4219
|
+
var import_store3 = __toESM(require_store(), 1);
|
|
4090
4220
|
var jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
|
|
4091
4221
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4092
4222
|
function StatusBar({ isProcessing }) {
|
|
4093
4223
|
const { isNarrow } = useLayout();
|
|
4224
|
+
const snapshot = import_config3.session;
|
|
4225
|
+
const state = import_store3.getSnapshot();
|
|
4094
4226
|
const [tick, setTick] = import_react_sb.useState(0);
|
|
4095
4227
|
import_react_sb.useEffect(() => {
|
|
4096
4228
|
const id = setInterval(() => setTick((t) => t + 1), 1000);
|
|
@@ -4103,11 +4235,12 @@ function StatusBar({ isProcessing }) {
|
|
|
4103
4235
|
const id = setInterval(() => setSpinFrame((f) => (f + 1) % SPINNER_FRAMES.length), 80);
|
|
4104
4236
|
return () => clearInterval(id);
|
|
4105
4237
|
}, [isProcessing]);
|
|
4106
|
-
const elapsed = (tick, ((Date.now() -
|
|
4107
|
-
const
|
|
4108
|
-
const
|
|
4238
|
+
const elapsed = (tick, ((Date.now() - snapshot.startTime) / 1000 / 60).toFixed(1));
|
|
4239
|
+
const tokStr = snapshot.totalTokens >= 1000 ? (snapshot.totalTokens / 1000).toFixed(1) + "k" : String(snapshot.totalTokens);
|
|
4240
|
+
const configReady = !state.needsConfig;
|
|
4241
|
+
const providerLabel = state.provider ? import_config3.PROVIDERS[state.provider]?.label || state.provider : "unknown";
|
|
4109
4242
|
return /* @__PURE__ */ jsx_runtime13.jsxs("box", {
|
|
4110
|
-
style: { flexDirection: "row", paddingLeft: isNarrow ? 1 : 2, paddingRight: isNarrow ? 1 : 2 },
|
|
4243
|
+
style: { flexDirection: "row", paddingLeft: isNarrow ? 1 : 2, paddingRight: isNarrow ? 1 : 2, paddingBottom: 1 },
|
|
4111
4244
|
children: [
|
|
4112
4245
|
/* @__PURE__ */ jsx_runtime13.jsx("box", {
|
|
4113
4246
|
style: { flexGrow: 1 },
|
|
@@ -4120,19 +4253,15 @@ function StatusBar({ isProcessing }) {
|
|
|
4120
4253
|
/* @__PURE__ */ jsx_runtime13.jsx("span", { fg: import_theme13.colors.dim, children: " \xB7 " }),
|
|
4121
4254
|
/* @__PURE__ */ jsx_runtime13.jsxs("span", {
|
|
4122
4255
|
fg: import_theme13.colors.dim,
|
|
4123
|
-
children: [turnCount, " turns"]
|
|
4256
|
+
children: [snapshot.turnCount, " turns"]
|
|
4124
4257
|
}),
|
|
4125
4258
|
!isNarrow ? /* @__PURE__ */ jsx_runtime13.jsxs(jsx_runtime13.Fragment, {
|
|
4126
4259
|
children: [
|
|
4127
4260
|
/* @__PURE__ */ jsx_runtime13.jsx("span", { fg: import_theme13.colors.dim, children: " \xB7 " }),
|
|
4128
4261
|
/* @__PURE__ */ jsx_runtime13.jsxs("span", {
|
|
4129
4262
|
fg: import_theme13.colors.dim,
|
|
4130
|
-
children: [toolCallCount, " tools"]
|
|
4131
|
-
})
|
|
4132
|
-
]
|
|
4133
|
-
}) : null,
|
|
4134
|
-
!isNarrow ? /* @__PURE__ */ jsx_runtime13.jsxs(jsx_runtime13.Fragment, {
|
|
4135
|
-
children: [
|
|
4263
|
+
children: [snapshot.toolCallCount, " tools"]
|
|
4264
|
+
}),
|
|
4136
4265
|
/* @__PURE__ */ jsx_runtime13.jsx("span", { fg: import_theme13.colors.dim, children: " \xB7 " }),
|
|
4137
4266
|
/* @__PURE__ */ jsx_runtime13.jsxs("span", {
|
|
4138
4267
|
fg: import_theme13.colors.dim,
|
|
@@ -4143,20 +4272,27 @@ function StatusBar({ isProcessing }) {
|
|
|
4143
4272
|
/* @__PURE__ */ jsx_runtime13.jsx("span", { fg: import_theme13.colors.dim, children: " \xB7 " }),
|
|
4144
4273
|
/* @__PURE__ */ jsx_runtime13.jsxs("span", {
|
|
4145
4274
|
fg: import_theme13.colors.dim,
|
|
4146
|
-
children: ["$", totalCost.toFixed(4)]
|
|
4147
|
-
})
|
|
4148
|
-
filesModified.size > 0 && !isNarrow ? /* @__PURE__ */ jsx_runtime13.jsxs(jsx_runtime13.Fragment, {
|
|
4149
|
-
children: [
|
|
4150
|
-
/* @__PURE__ */ jsx_runtime13.jsx("span", { fg: import_theme13.colors.dim, children: " \xB7 " }),
|
|
4151
|
-
/* @__PURE__ */ jsx_runtime13.jsxs("span", {
|
|
4152
|
-
fg: import_theme13.colors.yellow,
|
|
4153
|
-
children: [filesModified.size, " modified"]
|
|
4154
|
-
})
|
|
4155
|
-
]
|
|
4156
|
-
}) : null
|
|
4275
|
+
children: ["$", snapshot.totalCost.toFixed(4)]
|
|
4276
|
+
})
|
|
4157
4277
|
]
|
|
4158
4278
|
})
|
|
4159
4279
|
}),
|
|
4280
|
+
!isNarrow ? /* @__PURE__ */ jsx_runtime13.jsxs("text", {
|
|
4281
|
+
children: [
|
|
4282
|
+
/* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
4283
|
+
fg: configReady ? import_theme13.colors.green : import_theme13.colors.yellow,
|
|
4284
|
+
children: configReady ? "\u25CF" : "\u25CB"
|
|
4285
|
+
}),
|
|
4286
|
+
/* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
4287
|
+
fg: import_theme13.colors.dim,
|
|
4288
|
+
children: " "
|
|
4289
|
+
}),
|
|
4290
|
+
/* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
4291
|
+
fg: import_theme13.colors.muted,
|
|
4292
|
+
children: configReady ? providerLabel : "setup required"
|
|
4293
|
+
})
|
|
4294
|
+
]
|
|
4295
|
+
}) : null,
|
|
4160
4296
|
isProcessing ? /* @__PURE__ */ jsx_runtime13.jsxs("text", {
|
|
4161
4297
|
children: [
|
|
4162
4298
|
/* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
@@ -4165,11 +4301,11 @@ function StatusBar({ isProcessing }) {
|
|
|
4165
4301
|
}),
|
|
4166
4302
|
/* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
4167
4303
|
fg: import_theme13.colors.accent,
|
|
4168
|
-
children: isNarrow ? "
|
|
4304
|
+
children: isNarrow ? " \u2026" : " thinking"
|
|
4169
4305
|
}),
|
|
4170
4306
|
!isNarrow ? /* @__PURE__ */ jsx_runtime13.jsx("span", {
|
|
4171
4307
|
fg: import_theme13.colors.dim,
|
|
4172
|
-
children: "\
|
|
4308
|
+
children: " \xB7 Esc"
|
|
4173
4309
|
}) : null
|
|
4174
4310
|
]
|
|
4175
4311
|
}) : null
|
|
@@ -4189,6 +4325,11 @@ var COMMANDS = [
|
|
|
4189
4325
|
{ cmd: "/git <cmd>", desc: "Run a git command" },
|
|
4190
4326
|
{ cmd: "/quit", desc: "Exit" }
|
|
4191
4327
|
];
|
|
4328
|
+
var QUICK_TIPS = [
|
|
4329
|
+
"Ctrl+C exits the app",
|
|
4330
|
+
"Esc closes overlays and thinking blocks",
|
|
4331
|
+
"On first launch, choose a provider and paste your API key"
|
|
4332
|
+
];
|
|
4192
4333
|
var TOOLS = [
|
|
4193
4334
|
"Read",
|
|
4194
4335
|
"Write",
|
|
@@ -4264,6 +4405,19 @@ function HelpModal({ onClose, onCommand }) {
|
|
|
4264
4405
|
})
|
|
4265
4406
|
}, cmd))
|
|
4266
4407
|
}),
|
|
4408
|
+
/* @__PURE__ */ jsx_runtime14.jsx("text", {
|
|
4409
|
+
fg: import_theme14.colors.white,
|
|
4410
|
+
attributes: TextAttributes.BOLD,
|
|
4411
|
+
style: { marginTop: 1 },
|
|
4412
|
+
content: "Quick Tips"
|
|
4413
|
+
}),
|
|
4414
|
+
/* @__PURE__ */ jsx_runtime14.jsx("box", {
|
|
4415
|
+
style: { flexDirection: "column", marginTop: 0 },
|
|
4416
|
+
children: QUICK_TIPS.map((tip) => /* @__PURE__ */ jsx_runtime14.jsx("text", {
|
|
4417
|
+
fg: import_theme14.colors.dim,
|
|
4418
|
+
content: `\u2022 ${tip}`
|
|
4419
|
+
}, tip))
|
|
4420
|
+
}),
|
|
4267
4421
|
/* @__PURE__ */ jsx_runtime14.jsx("text", {
|
|
4268
4422
|
fg: import_theme14.colors.white,
|
|
4269
4423
|
attributes: TextAttributes.BOLD,
|
|
@@ -4304,7 +4458,7 @@ var import_useLayout = __toESM(require_useLayout(), 1);
|
|
|
4304
4458
|
var jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
4305
4459
|
var PROVIDER_ORDER = ["fireworks", "openai", "openrouter", "groq", "gemini", "together"];
|
|
4306
4460
|
var PROVIDER_EMOJI = {
|
|
4307
|
-
fireworks: "\
|
|
4461
|
+
fireworks: "\uD83D\uDD25",
|
|
4308
4462
|
openai: "\uD83E\uDD16",
|
|
4309
4463
|
openrouter: "\uD83D\uDD00",
|
|
4310
4464
|
groq: "\u26A1",
|
|
@@ -4320,34 +4474,62 @@ function ProviderSelector() {
|
|
|
4320
4474
|
var providers = import_config.PROVIDERS;
|
|
4321
4475
|
var providerKey = PROVIDER_ORDER[focusedIdx];
|
|
4322
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
|
+
}
|
|
4323
4483
|
function isConfigured(key) {
|
|
4324
|
-
|
|
4325
|
-
var hasEnv = Boolean(process.env[envKey]);
|
|
4326
|
-
var hasStored = key === state.provider && Boolean(state.apiKey);
|
|
4327
|
-
return hasEnv || hasStored;
|
|
4484
|
+
return loginState(key) !== "empty";
|
|
4328
4485
|
}
|
|
4329
|
-
function
|
|
4330
|
-
return key ===
|
|
4486
|
+
function isLoggedIn(key) {
|
|
4487
|
+
return loginState(key) === "logged-in";
|
|
4331
4488
|
}
|
|
4332
|
-
function
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
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
|
+
});
|
|
4496
|
+
}
|
|
4497
|
+
function handleLogin() {
|
|
4498
|
+
var key = input.trim();
|
|
4499
|
+
if (!key)
|
|
4500
|
+
return;
|
|
4501
|
+
finishLogin(providerKey, key);
|
|
4502
|
+
setInput("");
|
|
4503
|
+
setStep("select");
|
|
4504
|
+
}
|
|
4505
|
+
function handleLogout() {
|
|
4506
|
+
var remaining = import_config.logoutProvider(providerKey);
|
|
4507
|
+
if (remaining) {
|
|
4336
4508
|
import_store.setState({
|
|
4337
|
-
apiKey:
|
|
4338
|
-
provider: providerKey,
|
|
4509
|
+
apiKey: remaining.apiKey,
|
|
4510
|
+
provider: remaining.providerKey,
|
|
4339
4511
|
needsConfig: false
|
|
4340
4512
|
});
|
|
4341
4513
|
} else {
|
|
4342
|
-
|
|
4514
|
+
import_store.setState({
|
|
4515
|
+
apiKey: "",
|
|
4516
|
+
provider: providerKey,
|
|
4517
|
+
needsConfig: true
|
|
4518
|
+
});
|
|
4343
4519
|
}
|
|
4520
|
+
setInput("");
|
|
4521
|
+
setStep("select");
|
|
4344
4522
|
}
|
|
4345
|
-
function
|
|
4346
|
-
|
|
4347
|
-
|
|
4523
|
+
function handleSelect() {
|
|
4524
|
+
if (isLoggedIn(providerKey)) {
|
|
4525
|
+
handleLogout();
|
|
4348
4526
|
return;
|
|
4349
|
-
|
|
4350
|
-
|
|
4527
|
+
}
|
|
4528
|
+
if (isConfigured(providerKey)) {
|
|
4529
|
+
finishLogin(providerKey, getStoredKey(providerKey));
|
|
4530
|
+
return;
|
|
4531
|
+
}
|
|
4532
|
+
setStep("key");
|
|
4351
4533
|
}
|
|
4352
4534
|
var handleKeyPress = function(key) {
|
|
4353
4535
|
if (step === "select") {
|
|
@@ -4361,21 +4543,25 @@ function ProviderSelector() {
|
|
|
4361
4543
|
});
|
|
4362
4544
|
} else if (key.name === "return" || key.name === "enter") {
|
|
4363
4545
|
handleSelect();
|
|
4546
|
+
} else if (key.name === "l") {
|
|
4547
|
+
if (isLoggedIn(providerKey))
|
|
4548
|
+
handleLogout();
|
|
4364
4549
|
}
|
|
4365
4550
|
} else {
|
|
4366
4551
|
if (key.name === "escape") {
|
|
4367
4552
|
setStep("select");
|
|
4368
4553
|
setInput("");
|
|
4369
4554
|
} else if (key.name === "return" || key.name === "enter") {
|
|
4370
|
-
|
|
4555
|
+
handleLogin();
|
|
4371
4556
|
}
|
|
4372
4557
|
}
|
|
4373
4558
|
};
|
|
4559
|
+
var selectedState = loginState(providerKey);
|
|
4374
4560
|
return jsx_runtime.jsx("box", {
|
|
4375
4561
|
style: {
|
|
4376
4562
|
flexDirection: "column",
|
|
4377
4563
|
flexGrow: 1,
|
|
4378
|
-
paddingTop:
|
|
4564
|
+
paddingTop: 2
|
|
4379
4565
|
},
|
|
4380
4566
|
onKeyDown: handleKeyPress,
|
|
4381
4567
|
focused: true,
|
|
@@ -4386,36 +4572,39 @@ function ProviderSelector() {
|
|
|
4386
4572
|
children: jsx_runtime.jsx("text", {
|
|
4387
4573
|
attributes: TextAttributes.BOLD,
|
|
4388
4574
|
fg: import_theme.colors.white,
|
|
4389
|
-
children: "
|
|
4575
|
+
children: "Choose your AI provider"
|
|
4390
4576
|
})
|
|
4391
4577
|
}),
|
|
4392
4578
|
jsx_runtime.jsx("box", {
|
|
4393
4579
|
style: { paddingLeft: 4, paddingRight: 4, marginBottom: 1 },
|
|
4394
4580
|
children: jsx_runtime.jsx("text", {
|
|
4395
4581
|
fg: import_theme.colors.dim,
|
|
4396
|
-
children: "\u2191\u2193 or j/k to navigate
|
|
4582
|
+
children: "Use \u2191\u2193 or j/k to navigate. Enter logs in or out depending on the selected provider's state."
|
|
4397
4583
|
})
|
|
4398
4584
|
}),
|
|
4399
4585
|
PROVIDER_ORDER.map(function(key, idx) {
|
|
4400
4586
|
var focused = idx === focusedIdx;
|
|
4401
|
-
var
|
|
4402
|
-
var
|
|
4403
|
-
var
|
|
4404
|
-
var statusText = def ? "\u2713 Active" : configured ? "\u2713 Configured" : "\u2717 Not configured";
|
|
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";
|
|
4405
4590
|
return jsx_runtime.jsxs("box", {
|
|
4406
4591
|
style: {
|
|
4407
4592
|
flexDirection: "row",
|
|
4408
|
-
paddingLeft:
|
|
4409
|
-
paddingRight: 4
|
|
4410
|
-
paddingTop: 0,
|
|
4411
|
-
paddingBottom: 0
|
|
4593
|
+
paddingLeft: 4,
|
|
4594
|
+
paddingRight: 4
|
|
4412
4595
|
},
|
|
4413
4596
|
onMouseEnter: function() {
|
|
4414
4597
|
setFocusedIdx(idx);
|
|
4415
4598
|
},
|
|
4416
4599
|
onMouseDown: function() {
|
|
4417
4600
|
setFocusedIdx(idx);
|
|
4418
|
-
|
|
4601
|
+
if (stateLabel === "logged-in") {
|
|
4602
|
+
handleLogout();
|
|
4603
|
+
} else if (stateLabel === "saved") {
|
|
4604
|
+
finishLogin(key, getStoredKey(key));
|
|
4605
|
+
} else {
|
|
4606
|
+
setStep("key");
|
|
4607
|
+
}
|
|
4419
4608
|
},
|
|
4420
4609
|
children: [
|
|
4421
4610
|
jsx_runtime.jsx("text", {
|
|
@@ -4443,7 +4632,7 @@ function ProviderSelector() {
|
|
|
4443
4632
|
style: { paddingLeft: 4, paddingRight: 4, marginTop: 2 },
|
|
4444
4633
|
children: jsx_runtime.jsx("text", {
|
|
4445
4634
|
fg: import_theme.colors.dim,
|
|
4446
|
-
children: "Keys are stored in ~/.apex-dev/config.json or
|
|
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."
|
|
4447
4636
|
})
|
|
4448
4637
|
})
|
|
4449
4638
|
]
|
|
@@ -4488,7 +4677,7 @@ function ProviderSelector() {
|
|
|
4488
4677
|
focused: true,
|
|
4489
4678
|
value: input,
|
|
4490
4679
|
onChange: setInput,
|
|
4491
|
-
onSubmit:
|
|
4680
|
+
onSubmit: handleLogin,
|
|
4492
4681
|
placeholder: "Paste your API key here...",
|
|
4493
4682
|
fg: import_theme.colors.text
|
|
4494
4683
|
})
|
|
@@ -4498,7 +4687,7 @@ function ProviderSelector() {
|
|
|
4498
4687
|
style: { paddingLeft: 4, paddingRight: 4 },
|
|
4499
4688
|
children: jsx_runtime.jsx("text", {
|
|
4500
4689
|
fg: import_theme.colors.dim,
|
|
4501
|
-
children: "Press Enter to
|
|
4690
|
+
children: "Press Enter to login"
|
|
4502
4691
|
})
|
|
4503
4692
|
})
|
|
4504
4693
|
]
|
|
@@ -4697,32 +4886,34 @@ function App() {
|
|
|
4697
4886
|
});
|
|
4698
4887
|
}
|
|
4699
4888
|
}, []);
|
|
4700
|
-
const
|
|
4889
|
+
const shouldShowSetup = process.env.APEX_DEV_NEEDS_CONFIG === "true" || state.needsConfig;
|
|
4701
4890
|
return /* @__PURE__ */ jsx_runtime15.jsxs("box", {
|
|
4702
4891
|
style: { flexDirection: "column", flexGrow: 1 },
|
|
4703
4892
|
children: [
|
|
4704
|
-
/* @__PURE__ */ jsx_runtime15.jsx(
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
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
|
+
})
|
|
4726
4917
|
]
|
|
4727
4918
|
});
|
|
4728
4919
|
}
|