@wanghuimvp/axon 0.4.0 → 0.4.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/cli.js +81 -34
- 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
|
};
|
|
@@ -820,6 +834,21 @@ ${truncate2(text, 2e3)}`);
|
|
|
820
834
|
return parts.join("\n\n");
|
|
821
835
|
}
|
|
822
836
|
|
|
837
|
+
// src/core/systemPrompt.ts
|
|
838
|
+
function buildSystemPrompt(opts) {
|
|
839
|
+
const identity = `You are the coding agent inside Axon, a command-line coding tool. Axon is the CLI program \u2014 it is NOT a language model. You are powered by the model "${opts.model}" via the ${opts.provider} provider. If the user asks which model or LLM you are, answer honestly: "${opts.model}" (via ${opts.provider}), running inside the Axon CLI. Never claim that "Axon" is a model.`;
|
|
840
|
+
const toolLine = opts.tools === "all" ? `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.` : `Use the read-only tools to inspect the project: read_file, list_dir, glob, grep.`;
|
|
841
|
+
const closing = `Explain briefly what you are doing. When the task is done, stop calling tools.`;
|
|
842
|
+
let prompt = `${identity}
|
|
843
|
+
|
|
844
|
+
${toolLine} ${closing}`;
|
|
845
|
+
if (opts.context) prompt += `
|
|
846
|
+
|
|
847
|
+
Project context:
|
|
848
|
+
${opts.context}`;
|
|
849
|
+
return prompt;
|
|
850
|
+
}
|
|
851
|
+
|
|
823
852
|
// src/ui/permissionController.ts
|
|
824
853
|
function createPermissionController() {
|
|
825
854
|
const sessionAllow = /* @__PURE__ */ new Set();
|
|
@@ -1046,36 +1075,54 @@ function App({ engine, controller, provider, model, yolo }) {
|
|
|
1046
1075
|
|
|
1047
1076
|
// src/ui/Setup.tsx
|
|
1048
1077
|
import { useState as useState2 } from "react";
|
|
1049
|
-
import { Box as Box5, Text as Text5 } from "ink";
|
|
1078
|
+
import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
|
|
1050
1079
|
import TextInput2 from "ink-text-input";
|
|
1051
1080
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1081
|
+
var SETUP_PROVIDERS = ["anthropic", "openai", "gemini"];
|
|
1052
1082
|
function trimmedKey(v) {
|
|
1053
1083
|
const t = v.trim();
|
|
1054
1084
|
return t ? t : null;
|
|
1055
1085
|
}
|
|
1086
|
+
function providerForDigit(input) {
|
|
1087
|
+
const idx = Number(input) - 1;
|
|
1088
|
+
return Number.isInteger(idx) && idx >= 0 && idx < SETUP_PROVIDERS.length ? SETUP_PROVIDERS[idx] : null;
|
|
1089
|
+
}
|
|
1056
1090
|
function Setup({
|
|
1057
|
-
|
|
1058
|
-
info,
|
|
1091
|
+
initialProvider,
|
|
1059
1092
|
onSubmit
|
|
1060
1093
|
}) {
|
|
1094
|
+
const start = SETUP_PROVIDERS.includes(initialProvider) ? initialProvider : "anthropic";
|
|
1095
|
+
const [provider, setProvider] = useState2(start);
|
|
1061
1096
|
const [value, setValue] = useState2("");
|
|
1097
|
+
useInput3((input) => {
|
|
1098
|
+
const picked = providerForDigit(input);
|
|
1099
|
+
if (picked) setProvider(picked);
|
|
1100
|
+
});
|
|
1101
|
+
const info = keyProviderInfo(provider);
|
|
1062
1102
|
const submit = (v) => {
|
|
1063
1103
|
const k = trimmedKey(v);
|
|
1064
|
-
if (k) onSubmit(k);
|
|
1104
|
+
if (k) onSubmit(provider, k);
|
|
1065
1105
|
};
|
|
1066
1106
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
1067
|
-
/* @__PURE__ */
|
|
1068
|
-
|
|
1069
|
-
provider,
|
|
1070
|
-
|
|
1071
|
-
|
|
1107
|
+
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "Welcome to Axon. Pick a provider, then paste its API key." }),
|
|
1108
|
+
SETUP_PROVIDERS.map((p, i) => /* @__PURE__ */ jsxs5(Text5, { color: p === provider ? "cyan" : "gray", children: [
|
|
1109
|
+
p === provider ? "\u276F" : " ",
|
|
1110
|
+
" [",
|
|
1111
|
+
i + 1,
|
|
1112
|
+
"] ",
|
|
1113
|
+
p
|
|
1114
|
+
] }, p)),
|
|
1072
1115
|
/* @__PURE__ */ jsxs5(Text5, { children: [
|
|
1073
|
-
"
|
|
1116
|
+
"Active: ",
|
|
1117
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: provider }),
|
|
1118
|
+
" \u2014 set ",
|
|
1074
1119
|
/* @__PURE__ */ jsx5(Text5, { bold: true, children: info.envVar }),
|
|
1075
|
-
"
|
|
1120
|
+
", or paste a key below to save it to ~/.axon/config.json."
|
|
1076
1121
|
] }),
|
|
1077
1122
|
info.url ? /* @__PURE__ */ jsxs5(Text5, { color: "gray", children: [
|
|
1078
|
-
"Get a
|
|
1123
|
+
"Get a ",
|
|
1124
|
+
provider,
|
|
1125
|
+
" key at: ",
|
|
1079
1126
|
info.url
|
|
1080
1127
|
] }) : null,
|
|
1081
1128
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
@@ -1087,29 +1134,33 @@ function Setup({
|
|
|
1087
1134
|
|
|
1088
1135
|
// src/ui/runTui.tsx
|
|
1089
1136
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1090
|
-
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
1137
|
function Root({ deps }) {
|
|
1092
|
-
const { cfg, controller, yolo,
|
|
1138
|
+
const { cfg, controller, yolo, buildEngine, persistKey } = deps;
|
|
1093
1139
|
const [ready, setReady] = useState3(hasUsableKey(cfg));
|
|
1094
1140
|
const engineRef = useRef(null);
|
|
1095
1141
|
if (ready && !engineRef.current) engineRef.current = buildEngine();
|
|
1096
1142
|
if (!ready || !engineRef.current) {
|
|
1097
|
-
const info = keyProviderInfo(cfg.provider);
|
|
1098
1143
|
return /* @__PURE__ */ jsx6(
|
|
1099
1144
|
Setup,
|
|
1100
1145
|
{
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
cfg.providers[
|
|
1146
|
+
initialProvider: cfg.provider,
|
|
1147
|
+
onSubmit: (provider, key) => {
|
|
1148
|
+
persistKey(provider, key);
|
|
1149
|
+
cfg.provider = provider;
|
|
1150
|
+
cfg.providers[provider] = { ...cfg.providers[provider] ?? {}, apiKey: key };
|
|
1106
1151
|
setReady(true);
|
|
1107
1152
|
}
|
|
1108
1153
|
}
|
|
1109
1154
|
);
|
|
1110
1155
|
}
|
|
1111
1156
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
1112
|
-
/* @__PURE__ */
|
|
1157
|
+
/* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
|
|
1158
|
+
"Axon \xB7 ",
|
|
1159
|
+
cfg.provider,
|
|
1160
|
+
"/",
|
|
1161
|
+
resolveModel(cfg),
|
|
1162
|
+
" \xB7 type a request, Ctrl+C to quit"
|
|
1163
|
+
] }),
|
|
1113
1164
|
/* @__PURE__ */ jsx6(
|
|
1114
1165
|
App,
|
|
1115
1166
|
{
|
|
@@ -1131,10 +1182,10 @@ function runTui(opts) {
|
|
|
1131
1182
|
cfg,
|
|
1132
1183
|
controller,
|
|
1133
1184
|
yolo: Boolean(opts.yolo),
|
|
1134
|
-
welcome: `Axon \xB7 ${cfg.provider}/${resolveModel(cfg)} \xB7 type a request, Ctrl+C to quit`,
|
|
1135
1185
|
persistKey: (provider, key) => {
|
|
1136
1186
|
try {
|
|
1137
1187
|
setApiKey(provider, key);
|
|
1188
|
+
setConfigValue("provider", provider);
|
|
1138
1189
|
} catch {
|
|
1139
1190
|
}
|
|
1140
1191
|
},
|
|
@@ -1143,10 +1194,7 @@ function runTui(opts) {
|
|
|
1143
1194
|
const tools = buildAllTools();
|
|
1144
1195
|
const gate = opts.yolo ? allowAllGate : controller.gate;
|
|
1145
1196
|
const context = loadProjectContext(process.cwd());
|
|
1146
|
-
const system =
|
|
1147
|
-
|
|
1148
|
-
Project context:
|
|
1149
|
-
${context}` : "");
|
|
1197
|
+
const system = buildSystemPrompt({ provider: cfg.provider, model: resolveModel(cfg), tools: "all", context });
|
|
1150
1198
|
return new Engine({ provider, tools, system, cwd: process.cwd(), gate });
|
|
1151
1199
|
}
|
|
1152
1200
|
};
|
|
@@ -1158,8 +1206,6 @@ ${context}` : "");
|
|
|
1158
1206
|
}
|
|
1159
1207
|
|
|
1160
1208
|
// src/cli.ts
|
|
1161
|
-
var READONLY_SYSTEM = `You are Axon, an agentic coding assistant. Use the read-only tools \u2014 read_file, list_dir, glob, grep \u2014 to inspect the project and answer precisely. When done, stop calling tools.`;
|
|
1162
|
-
var YOLO_SYSTEM = `You are Axon, an agentic coding assistant. Use the provided 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). Prefer edit_file for surgical changes. When done, stop calling tools.`;
|
|
1163
1209
|
function redactKeys(cfg) {
|
|
1164
1210
|
const providers = cfg.providers;
|
|
1165
1211
|
if (!providers || typeof providers !== "object") return cfg;
|
|
@@ -1205,12 +1251,13 @@ async function main(opts) {
|
|
|
1205
1251
|
const provider = createProvider(cfg);
|
|
1206
1252
|
const tools = opts.yolo ? buildAllTools() : buildReadOnlyTools();
|
|
1207
1253
|
const gate = opts.yolo ? allowAllGate : denyGate;
|
|
1208
|
-
const baseSystem = opts.yolo ? YOLO_SYSTEM : READONLY_SYSTEM;
|
|
1209
1254
|
const context = loadProjectContext(process.cwd());
|
|
1210
|
-
const system =
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1255
|
+
const system = buildSystemPrompt({
|
|
1256
|
+
provider: cfg.provider,
|
|
1257
|
+
model: resolveModel(cfg),
|
|
1258
|
+
tools: opts.yolo ? "all" : "readonly",
|
|
1259
|
+
context
|
|
1260
|
+
});
|
|
1214
1261
|
const engine = new Engine({ provider, tools, system, cwd: process.cwd(), gate });
|
|
1215
1262
|
printRunner(engine, (s) => process.stdout.write(s));
|
|
1216
1263
|
process.stderr.write(`[axon: ${cfg.provider} / ${resolveModel(cfg)}${opts.yolo ? " / yolo" : ""}]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wanghuimvp/axon",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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": {
|