@wanghuimvp/axon 0.4.0 → 0.4.1
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/cli.js +59 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -23,6 +23,20 @@ var DEFAULTS = {
|
|
|
23
23
|
gemini: { apiKey: "env:GEMINI_API_KEY" }
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
+
var ENV_VARS = {
|
|
27
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
28
|
+
openai: "OPENAI_API_KEY",
|
|
29
|
+
gemini: "GEMINI_API_KEY"
|
|
30
|
+
};
|
|
31
|
+
function detectProvider(fileCfg) {
|
|
32
|
+
for (const name of ["anthropic", "openai", "gemini"]) {
|
|
33
|
+
const literal = fileCfg.providers?.[name]?.apiKey;
|
|
34
|
+
const hasLiteral = typeof literal === "string" && !literal.startsWith("env:") && literal.trim().length > 0;
|
|
35
|
+
const hasEnv = (process.env[ENV_VARS[name]] ?? "").trim().length > 0;
|
|
36
|
+
if (hasLiteral || hasEnv) return name;
|
|
37
|
+
}
|
|
38
|
+
return "anthropic";
|
|
39
|
+
}
|
|
26
40
|
function resolveModel(cfg) {
|
|
27
41
|
const model = cfg.model ?? cfg.providers[cfg.provider]?.model ?? DEFAULT_MODELS[cfg.provider];
|
|
28
42
|
if (!model) {
|
|
@@ -46,7 +60,7 @@ function loadConfig() {
|
|
|
46
60
|
} catch {
|
|
47
61
|
}
|
|
48
62
|
const merged = {
|
|
49
|
-
provider: fileCfg.provider ??
|
|
63
|
+
provider: fileCfg.provider ?? detectProvider(fileCfg),
|
|
50
64
|
model: fileCfg.model,
|
|
51
65
|
providers: { ...DEFAULTS.providers, ...fileCfg.providers ?? {} }
|
|
52
66
|
};
|
|
@@ -1046,36 +1060,54 @@ function App({ engine, controller, provider, model, yolo }) {
|
|
|
1046
1060
|
|
|
1047
1061
|
// src/ui/Setup.tsx
|
|
1048
1062
|
import { useState as useState2 } from "react";
|
|
1049
|
-
import { Box as Box5, Text as Text5 } from "ink";
|
|
1063
|
+
import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
|
|
1050
1064
|
import TextInput2 from "ink-text-input";
|
|
1051
1065
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1066
|
+
var SETUP_PROVIDERS = ["anthropic", "openai", "gemini"];
|
|
1052
1067
|
function trimmedKey(v) {
|
|
1053
1068
|
const t = v.trim();
|
|
1054
1069
|
return t ? t : null;
|
|
1055
1070
|
}
|
|
1071
|
+
function providerForDigit(input) {
|
|
1072
|
+
const idx = Number(input) - 1;
|
|
1073
|
+
return Number.isInteger(idx) && idx >= 0 && idx < SETUP_PROVIDERS.length ? SETUP_PROVIDERS[idx] : null;
|
|
1074
|
+
}
|
|
1056
1075
|
function Setup({
|
|
1057
|
-
|
|
1058
|
-
info,
|
|
1076
|
+
initialProvider,
|
|
1059
1077
|
onSubmit
|
|
1060
1078
|
}) {
|
|
1079
|
+
const start = SETUP_PROVIDERS.includes(initialProvider) ? initialProvider : "anthropic";
|
|
1080
|
+
const [provider, setProvider] = useState2(start);
|
|
1061
1081
|
const [value, setValue] = useState2("");
|
|
1082
|
+
useInput3((input) => {
|
|
1083
|
+
const picked = providerForDigit(input);
|
|
1084
|
+
if (picked) setProvider(picked);
|
|
1085
|
+
});
|
|
1086
|
+
const info = keyProviderInfo(provider);
|
|
1062
1087
|
const submit = (v) => {
|
|
1063
1088
|
const k = trimmedKey(v);
|
|
1064
|
-
if (k) onSubmit(k);
|
|
1089
|
+
if (k) onSubmit(provider, k);
|
|
1065
1090
|
};
|
|
1066
1091
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
1067
|
-
/* @__PURE__ */
|
|
1068
|
-
|
|
1069
|
-
provider,
|
|
1070
|
-
|
|
1071
|
-
|
|
1092
|
+
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "Welcome to Axon. Pick a provider, then paste its API key." }),
|
|
1093
|
+
SETUP_PROVIDERS.map((p, i) => /* @__PURE__ */ jsxs5(Text5, { color: p === provider ? "cyan" : "gray", children: [
|
|
1094
|
+
p === provider ? "\u276F" : " ",
|
|
1095
|
+
" [",
|
|
1096
|
+
i + 1,
|
|
1097
|
+
"] ",
|
|
1098
|
+
p
|
|
1099
|
+
] }, p)),
|
|
1072
1100
|
/* @__PURE__ */ jsxs5(Text5, { children: [
|
|
1073
|
-
"
|
|
1101
|
+
"Active: ",
|
|
1102
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: provider }),
|
|
1103
|
+
" \u2014 set ",
|
|
1074
1104
|
/* @__PURE__ */ jsx5(Text5, { bold: true, children: info.envVar }),
|
|
1075
|
-
"
|
|
1105
|
+
", or paste a key below to save it to ~/.axon/config.json."
|
|
1076
1106
|
] }),
|
|
1077
1107
|
info.url ? /* @__PURE__ */ jsxs5(Text5, { color: "gray", children: [
|
|
1078
|
-
"Get a
|
|
1108
|
+
"Get a ",
|
|
1109
|
+
provider,
|
|
1110
|
+
" key at: ",
|
|
1079
1111
|
info.url
|
|
1080
1112
|
] }) : null,
|
|
1081
1113
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
@@ -1089,27 +1121,32 @@ function Setup({
|
|
|
1089
1121
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1090
1122
|
var TUI_SYSTEM = `You are Axon, an interactive agentic coding assistant. Use the tools to inspect and modify the project: read_file, list_dir, glob, grep (read-only) and write_file, edit_file, shell (these change the workspace; the user is prompted to approve each). Prefer edit_file for surgical changes. Explain briefly what you are doing.`;
|
|
1091
1123
|
function Root({ deps }) {
|
|
1092
|
-
const { cfg, controller, yolo,
|
|
1124
|
+
const { cfg, controller, yolo, buildEngine, persistKey } = deps;
|
|
1093
1125
|
const [ready, setReady] = useState3(hasUsableKey(cfg));
|
|
1094
1126
|
const engineRef = useRef(null);
|
|
1095
1127
|
if (ready && !engineRef.current) engineRef.current = buildEngine();
|
|
1096
1128
|
if (!ready || !engineRef.current) {
|
|
1097
|
-
const info = keyProviderInfo(cfg.provider);
|
|
1098
1129
|
return /* @__PURE__ */ jsx6(
|
|
1099
1130
|
Setup,
|
|
1100
1131
|
{
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
cfg.providers[
|
|
1132
|
+
initialProvider: cfg.provider,
|
|
1133
|
+
onSubmit: (provider, key) => {
|
|
1134
|
+
persistKey(provider, key);
|
|
1135
|
+
cfg.provider = provider;
|
|
1136
|
+
cfg.providers[provider] = { ...cfg.providers[provider] ?? {}, apiKey: key };
|
|
1106
1137
|
setReady(true);
|
|
1107
1138
|
}
|
|
1108
1139
|
}
|
|
1109
1140
|
);
|
|
1110
1141
|
}
|
|
1111
1142
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
1112
|
-
/* @__PURE__ */
|
|
1143
|
+
/* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
|
|
1144
|
+
"Axon \xB7 ",
|
|
1145
|
+
cfg.provider,
|
|
1146
|
+
"/",
|
|
1147
|
+
resolveModel(cfg),
|
|
1148
|
+
" \xB7 type a request, Ctrl+C to quit"
|
|
1149
|
+
] }),
|
|
1113
1150
|
/* @__PURE__ */ jsx6(
|
|
1114
1151
|
App,
|
|
1115
1152
|
{
|
|
@@ -1131,10 +1168,10 @@ function runTui(opts) {
|
|
|
1131
1168
|
cfg,
|
|
1132
1169
|
controller,
|
|
1133
1170
|
yolo: Boolean(opts.yolo),
|
|
1134
|
-
welcome: `Axon \xB7 ${cfg.provider}/${resolveModel(cfg)} \xB7 type a request, Ctrl+C to quit`,
|
|
1135
1171
|
persistKey: (provider, key) => {
|
|
1136
1172
|
try {
|
|
1137
1173
|
setApiKey(provider, key);
|
|
1174
|
+
setConfigValue("provider", provider);
|
|
1138
1175
|
} catch {
|
|
1139
1176
|
}
|
|
1140
1177
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wanghuimvp/axon",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Axon — a multi-provider agentic coding CLI (Anthropic, OpenAI + OpenAI-compatible endpoints, Gemini). Runs a multi-step tool loop over your codebase.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|