@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.
Files changed (2) hide show
  1. package/dist/cli.js +81 -34
  2. 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 ?? DEFAULTS.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
- provider,
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__ */ jsxs5(Text5, { color: "yellow", children: [
1068
- 'No API key found for "',
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
- "Set ",
1116
+ "Active: ",
1117
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: provider }),
1118
+ " \u2014 set ",
1074
1119
  /* @__PURE__ */ jsx5(Text5, { bold: true, children: info.envVar }),
1075
- " in your environment, or paste a key below to save it to ~/.axon/config.json."
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 key at: ",
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, welcome, buildEngine, persistKey } = deps;
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
- provider: cfg.provider,
1102
- info,
1103
- onSubmit: (key) => {
1104
- persistKey(cfg.provider, key);
1105
- cfg.providers[cfg.provider] = { ...cfg.providers[cfg.provider] ?? {}, apiKey: key };
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__ */ jsx6(Text6, { color: "green", children: welcome }),
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 = TUI_SYSTEM + (context ? `
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 = baseSystem + (context ? `
1211
-
1212
- Project context:
1213
- ${context}` : "");
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.0",
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": {