@offerpilot/axiomruntime 0.0.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/README.md +185 -0
- package/dist/cli/commands/add.js +29 -0
- package/dist/cli/commands/context.js +29 -0
- package/dist/cli/commands/doctor.js +62 -0
- package/dist/cli/commands/edit.js +85 -0
- package/dist/cli/commands/help.js +16 -0
- package/dist/cli/commands/list.js +25 -0
- package/dist/cli/commands/log.js +63 -0
- package/dist/cli/commands/memory.js +241 -0
- package/dist/cli/commands/report.js +35 -0
- package/dist/cli/commands/session.js +74 -0
- package/dist/cli/commands/setup.js +86 -0
- package/dist/cli/commands/status.js +50 -0
- package/dist/cli/commands/telegram.js +701 -0
- package/dist/cli/commands/use.js +108 -0
- package/dist/cli/commands/version.js +12 -0
- package/dist/cli/index.js +276 -0
- package/dist/cli/output/table.js +22 -0
- package/dist/cli/prompts/prompt.js +37 -0
- package/dist/cli/registry.js +16 -0
- package/dist/core/config/cache-store.js +193 -0
- package/dist/core/config/json-store.js +114 -0
- package/dist/core/config/paths.js +85 -0
- package/dist/core/config/providers-store.js +89 -0
- package/dist/core/config/schema.js +60 -0
- package/dist/core/config/session-store.js +30 -0
- package/dist/core/config/usage-store.js +18 -0
- package/dist/core/context/context-service.js +186 -0
- package/dist/core/integrations/integration-state.js +105 -0
- package/dist/core/logs/log-service.js +56 -0
- package/dist/core/memory/embedding-check.js +121 -0
- package/dist/core/memory/memory-config.js +122 -0
- package/dist/core/models/model-discovery.js +430 -0
- package/dist/core/models/model-filter.js +13 -0
- package/dist/core/providers/provider-service.js +212 -0
- package/dist/core/reports/report-service.js +166 -0
- package/dist/core/runner/command-resolver.js +60 -0
- package/dist/core/runner/engine-registry.js +93 -0
- package/dist/core/runner/fallback.js +114 -0
- package/dist/core/runner/openai-usage-http.js +82 -0
- package/dist/core/runner/openai-usage-proxy.js +1 -0
- package/dist/core/runner/openai-usage-recording.js +172 -0
- package/dist/core/runner/openai-usage-responses.js +469 -0
- package/dist/core/runner/openai-usage-server.js +319 -0
- package/dist/core/runner/openai-usage-types.js +1 -0
- package/dist/core/runner/tool-runner.js +138 -0
- package/dist/core/sessions/session-service.js +47 -0
- package/dist/core/status/doctor-service.js +391 -0
- package/dist/core/status/status-service.js +60 -0
- package/dist/core/types.js +1 -0
- package/dist/core/usage/pricing.js +113 -0
- package/dist/core/usage/usage-service.js +30 -0
- package/dist/core/utils/is-record.js +3 -0
- package/dist/server/index.js +28 -0
- package/dist/server/runtime-server.js +430 -0
- package/dist/telegram/bot-registry.js +80 -0
- package/dist/telegram/bot.js +128 -0
- package/dist/telegram/config.js +235 -0
- package/dist/telegram/engine/claude-engine.js +240 -0
- package/dist/telegram/engine/codex-engine.js +437 -0
- package/dist/telegram/engine/engine-utils.js +67 -0
- package/dist/telegram/engine/process-utils.js +132 -0
- package/dist/telegram/engine/registry.js +31 -0
- package/dist/telegram/engine/types.js +1 -0
- package/dist/telegram/handler-registry.js +28 -0
- package/dist/telegram/handlers/callback.js +311 -0
- package/dist/telegram/handlers/command.js +272 -0
- package/dist/telegram/handlers/document.js +108 -0
- package/dist/telegram/handlers/memory.js +305 -0
- package/dist/telegram/handlers/message.js +701 -0
- package/dist/telegram/handlers/provider.js +332 -0
- package/dist/telegram/handlers/setup.js +527 -0
- package/dist/telegram/handlers/usage.js +124 -0
- package/dist/telegram/index.js +93 -0
- package/dist/telegram/interaction/approval.js +108 -0
- package/dist/telegram/interaction/command-menu.js +253 -0
- package/dist/telegram/interaction/formatter.js +487 -0
- package/dist/telegram/interaction/keyboards.js +145 -0
- package/dist/telegram/interaction/progress-reporter.js +160 -0
- package/dist/telegram/interaction/prompt-middleware.js +168 -0
- package/dist/telegram/interaction/result-store.js +41 -0
- package/dist/telegram/interaction/token-budget.js +21 -0
- package/dist/telegram/interaction/tool-name.js +41 -0
- package/dist/telegram/lifecycle-registry.js +47 -0
- package/dist/telegram/log.js +46 -0
- package/dist/telegram/memory/memory-inject.js +52 -0
- package/dist/telegram/memory/memory-service.js +413 -0
- package/dist/telegram/memory/memory-store.js +216 -0
- package/dist/telegram/memory/types.js +1 -0
- package/dist/telegram/network-retry.js +22 -0
- package/dist/telegram/network.js +53 -0
- package/dist/telegram/session/manager.js +229 -0
- package/dist/telegram/session/store.js +363 -0
- package/dist/telegram/session/types.js +1 -0
- package/dist/telegram/supervisor.js +57 -0
- package/dist/telegram/templates/messages.js +1 -0
- package/docs/README.md +98 -0
- package/docs/USAGE.html +853 -0
- package/package.json +57 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { checkAndRecordMemoryEmbeddingConfig } from "../../core/memory/embedding-check.js";
|
|
2
|
+
import { clearMemoryEmbeddingConfig, getMemoryEmbeddingConfig, setMemoryEmbeddingConfig } from "../../core/memory/memory-config.js";
|
|
3
|
+
import { writeLog } from "../../core/logs/log-service.js";
|
|
4
|
+
import { maskSecret } from "../output/table.js";
|
|
5
|
+
import { promptConfirm, promptSelect, promptText } from "../prompts/prompt.js";
|
|
6
|
+
export async function runMemoryCommand(args) {
|
|
7
|
+
const [area, action, ...rest] = args;
|
|
8
|
+
if (area === undefined || area === "embedding" || area === "vector") {
|
|
9
|
+
await runMemoryEmbeddingCommand(area === undefined ? args : [action, ...rest].filter((item) => Boolean(item)));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`Unknown memory command: ${area}`);
|
|
13
|
+
}
|
|
14
|
+
async function runMemoryEmbeddingCommand(args) {
|
|
15
|
+
if (!args.length) {
|
|
16
|
+
await runMemoryEmbeddingInteractive();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const [action = "show", ...rest] = args;
|
|
20
|
+
if (action === "show" || action === "status") {
|
|
21
|
+
await showMemoryEmbeddingConfig();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (action === "set" || action === "edit") {
|
|
25
|
+
await setEmbeddingConfig(rest);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (action === "test" || action === "check") {
|
|
29
|
+
await testEmbeddingConfig(rest.join(" ").trim() || undefined);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (action === "clear" || action === "delete" || action === "remove") {
|
|
33
|
+
await clearEmbeddingConfig();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Unknown memory embedding command: ${action}`);
|
|
37
|
+
}
|
|
38
|
+
async function runMemoryEmbeddingInteractive() {
|
|
39
|
+
const config = await getMemoryEmbeddingConfig();
|
|
40
|
+
const action = await promptSelect("Memory embedding", [
|
|
41
|
+
{ label: config ? `show current config (${config.name} / ${config.model})` : "show current config", value: "show" },
|
|
42
|
+
{ label: config ? "edit embedding model" : "set embedding model", value: "set" },
|
|
43
|
+
...(config ? [
|
|
44
|
+
{ label: "test embedding model", value: "test" },
|
|
45
|
+
{ label: "clear embedding model", value: "clear" }
|
|
46
|
+
] : []),
|
|
47
|
+
{ label: "exit", value: "exit" }
|
|
48
|
+
]);
|
|
49
|
+
if (action === "exit")
|
|
50
|
+
return;
|
|
51
|
+
if (action === "show") {
|
|
52
|
+
await showMemoryEmbeddingConfig();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (action === "set") {
|
|
56
|
+
await setEmbeddingConfig([]);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (action === "test") {
|
|
60
|
+
await testEmbeddingConfig();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (action === "clear") {
|
|
64
|
+
await clearEmbeddingConfig();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function showMemoryEmbeddingConfig() {
|
|
68
|
+
const config = await getMemoryEmbeddingConfig();
|
|
69
|
+
if (!config) {
|
|
70
|
+
console.log("No memory embedding model configured.");
|
|
71
|
+
console.log("Run `ai memory embedding set` to configure one.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
printEmbeddingConfig(config);
|
|
75
|
+
}
|
|
76
|
+
async function setEmbeddingConfig(args) {
|
|
77
|
+
const options = parseSetOptions(args);
|
|
78
|
+
const positional = parseSetPositionals(args);
|
|
79
|
+
const existing = await getMemoryEmbeddingConfig();
|
|
80
|
+
const interactive = positional.length < 4;
|
|
81
|
+
const name = positional[0] ?? await promptText("Embedding provider name", { defaultValue: existing?.name ?? "jina" });
|
|
82
|
+
const baseUrl = positional[1] ?? await promptText("Embedding base URL", { defaultValue: existing?.baseUrl ?? "https://api.jina.ai/v1" });
|
|
83
|
+
const apiKey = positional[2] ?? await promptApiKey(existing?.apiKey);
|
|
84
|
+
const model = positional[3] ?? await promptText("Embedding model", { defaultValue: existing?.model ?? "jina-embeddings-v3" });
|
|
85
|
+
const providerType = options.providerType ?? (interactive
|
|
86
|
+
? await promptSelect("Embedding API type", [
|
|
87
|
+
{ label: "jina", value: "jina" },
|
|
88
|
+
{ label: "openai-compatible", value: "openai-compatible" }
|
|
89
|
+
])
|
|
90
|
+
: undefined);
|
|
91
|
+
const queryTask = options.queryTask ?? (interactive && providerType === "jina"
|
|
92
|
+
? await promptText("Query task", { defaultValue: existing?.queryTask ?? "retrieval.query" })
|
|
93
|
+
: undefined);
|
|
94
|
+
const passageTask = options.passageTask ?? (interactive && providerType === "jina"
|
|
95
|
+
? await promptText("Passage task", { defaultValue: existing?.passageTask ?? "retrieval.passage" })
|
|
96
|
+
: undefined);
|
|
97
|
+
const dimensions = options.dimensions ?? null;
|
|
98
|
+
const config = await setMemoryEmbeddingConfig({
|
|
99
|
+
name,
|
|
100
|
+
baseUrl,
|
|
101
|
+
apiKey,
|
|
102
|
+
model,
|
|
103
|
+
providerType,
|
|
104
|
+
queryTask,
|
|
105
|
+
passageTask,
|
|
106
|
+
dimensions
|
|
107
|
+
});
|
|
108
|
+
console.log(`Configured memory embedding model: ${config.name} / ${config.model}`);
|
|
109
|
+
if (!options.skipTest) {
|
|
110
|
+
const result = await checkAndRecordMemoryEmbeddingConfig(config);
|
|
111
|
+
if (result.status === "ok") {
|
|
112
|
+
console.log(`Embedding check: ok (${result.dimensions} dimensions)`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(`Embedding check: error (${result.error})`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
await writeLog({
|
|
119
|
+
category: "system",
|
|
120
|
+
action: "memory_embedding_config_set",
|
|
121
|
+
message: `Configured memory embedding model: ${config.name} / ${config.model}`,
|
|
122
|
+
metadata: { name: config.name, baseUrl: config.baseUrl, model: config.model, providerType: config.providerType }
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
async function testEmbeddingConfig(text = "ping") {
|
|
126
|
+
const config = await getMemoryEmbeddingConfig();
|
|
127
|
+
if (!config) {
|
|
128
|
+
console.log("No memory embedding model configured.");
|
|
129
|
+
console.log("Run `ai memory embedding set` first.");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const result = await checkAndRecordMemoryEmbeddingConfig(config, text);
|
|
133
|
+
if (result.status === "ok") {
|
|
134
|
+
console.log(`Memory embedding check: ok`);
|
|
135
|
+
console.log(`Model: ${result.model}`);
|
|
136
|
+
console.log(`Dimensions: ${result.dimensions}`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
console.log("Memory embedding check: error");
|
|
140
|
+
console.log(result.error);
|
|
141
|
+
}
|
|
142
|
+
async function clearEmbeddingConfig() {
|
|
143
|
+
const config = await getMemoryEmbeddingConfig();
|
|
144
|
+
if (!config) {
|
|
145
|
+
console.log("No memory embedding model configured.");
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const confirmed = await promptConfirm(`Clear memory embedding model ${config.name} / ${config.model}?`, false);
|
|
149
|
+
if (!confirmed) {
|
|
150
|
+
console.log("Clear cancelled.");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await clearMemoryEmbeddingConfig();
|
|
154
|
+
console.log("Cleared memory embedding model config.");
|
|
155
|
+
await writeLog({
|
|
156
|
+
category: "system",
|
|
157
|
+
action: "memory_embedding_config_clear",
|
|
158
|
+
message: `Cleared memory embedding model config: ${config.name} / ${config.model}`,
|
|
159
|
+
metadata: { name: config.name, model: config.model }
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function printEmbeddingConfig(config) {
|
|
163
|
+
console.log("Memory Embedding Model");
|
|
164
|
+
console.log("=".repeat(72));
|
|
165
|
+
console.log(` Name ${config.name}`);
|
|
166
|
+
console.log(` Base URL ${config.baseUrl}`);
|
|
167
|
+
console.log(` API Key ${maskSecret(config.apiKey)}`);
|
|
168
|
+
console.log(` Type ${config.providerType}`);
|
|
169
|
+
console.log(` Model ${config.model}`);
|
|
170
|
+
console.log(` Query ${config.queryTask ?? "(default)"}`);
|
|
171
|
+
console.log(` Passage ${config.passageTask ?? "(default)"}`);
|
|
172
|
+
console.log(` Dims ${config.dimensions ?? "(unknown)"}`);
|
|
173
|
+
console.log(` Checked ${config.lastCheckedAt ?? "(never)"}`);
|
|
174
|
+
if (config.lastError)
|
|
175
|
+
console.log(` Error ${config.lastError}`);
|
|
176
|
+
}
|
|
177
|
+
function parseSetOptions(args) {
|
|
178
|
+
const options = { skipTest: false };
|
|
179
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
180
|
+
const arg = args[index];
|
|
181
|
+
if (arg === "--skip-test") {
|
|
182
|
+
options.skipTest = true;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (arg === "--type" || arg === "--provider-type") {
|
|
186
|
+
options.providerType = parseProviderType(readOptionValue(args, index, arg));
|
|
187
|
+
index += 1;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (arg === "--query-task") {
|
|
191
|
+
options.queryTask = readOptionValue(args, index, arg);
|
|
192
|
+
index += 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (arg === "--passage-task") {
|
|
196
|
+
options.passageTask = readOptionValue(args, index, arg);
|
|
197
|
+
index += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (arg === "--dimensions") {
|
|
201
|
+
const dimensions = Number(readOptionValue(args, index, arg));
|
|
202
|
+
if (!Number.isInteger(dimensions) || dimensions <= 0) {
|
|
203
|
+
throw new Error("--dimensions must be a positive integer.");
|
|
204
|
+
}
|
|
205
|
+
options.dimensions = dimensions;
|
|
206
|
+
index += 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return options;
|
|
210
|
+
}
|
|
211
|
+
function parseSetPositionals(args) {
|
|
212
|
+
const values = [];
|
|
213
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
214
|
+
const arg = args[index];
|
|
215
|
+
if (arg === "--skip-test")
|
|
216
|
+
continue;
|
|
217
|
+
if (arg.startsWith("--")) {
|
|
218
|
+
index += 1;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
values.push(arg);
|
|
222
|
+
}
|
|
223
|
+
return values;
|
|
224
|
+
}
|
|
225
|
+
async function promptApiKey(existing) {
|
|
226
|
+
const message = existing ? "Embedding API key (leave blank to keep current)" : "Embedding API key";
|
|
227
|
+
const value = await promptText(message);
|
|
228
|
+
return value || existing || "";
|
|
229
|
+
}
|
|
230
|
+
function readOptionValue(args, index, option) {
|
|
231
|
+
const value = args[index + 1];
|
|
232
|
+
if (!value || value.startsWith("--")) {
|
|
233
|
+
throw new Error(`${option} requires a value.`);
|
|
234
|
+
}
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
function parseProviderType(value) {
|
|
238
|
+
if (value === "jina" || value === "openai-compatible")
|
|
239
|
+
return value;
|
|
240
|
+
throw new Error("--type must be jina or openai-compatible.");
|
|
241
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { generateSessionReport } from "../../core/reports/report-service.js";
|
|
3
|
+
import { listRecentSessions } from "../../core/sessions/session-service.js";
|
|
4
|
+
import { promptSelect } from "../prompts/prompt.js";
|
|
5
|
+
export async function runReportCommand(args) {
|
|
6
|
+
const shouldPrint = args.includes("--print");
|
|
7
|
+
const sessionId = args.find((arg) => arg !== "--print") ?? await selectSession();
|
|
8
|
+
const report = await generateSessionReport(sessionId);
|
|
9
|
+
if (shouldPrint) {
|
|
10
|
+
console.log(report.content);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
await openFile(report.filePath);
|
|
14
|
+
console.log(`Opened report file: ${report.filePath}`);
|
|
15
|
+
}
|
|
16
|
+
async function selectSession() {
|
|
17
|
+
const sessions = await listRecentSessions(20);
|
|
18
|
+
if (!sessions.length) {
|
|
19
|
+
throw new Error("No sessions found. Run `ai use` first.");
|
|
20
|
+
}
|
|
21
|
+
return promptSelect("Select session for report", sessions.map((session) => ({ label: formatSessionLabel(session), value: session.id })));
|
|
22
|
+
}
|
|
23
|
+
function formatSessionLabel(session) {
|
|
24
|
+
return `${session.startedAt} ${session.tool} ${session.provider} ${session.model} ${session.status}`;
|
|
25
|
+
}
|
|
26
|
+
async function openFile(filePath) {
|
|
27
|
+
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
28
|
+
const args = process.platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
|
|
29
|
+
await new Promise((resolve) => {
|
|
30
|
+
const child = spawn(opener, args, { stdio: "ignore", detached: true });
|
|
31
|
+
child.on("error", () => resolve());
|
|
32
|
+
child.on("close", () => resolve());
|
|
33
|
+
child.unref();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { clearAllSessions, getSession, listRecentSessions } from "../../core/sessions/session-service.js";
|
|
2
|
+
import { writeLog } from "../../core/logs/log-service.js";
|
|
3
|
+
import { promptSelect } from "../prompts/prompt.js";
|
|
4
|
+
import { runUseCommand } from "./use.js";
|
|
5
|
+
export async function runSessionCommand(args) {
|
|
6
|
+
const subcommand = args[0];
|
|
7
|
+
if (subcommand === "list") {
|
|
8
|
+
await printSessions();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (subcommand === "clear") {
|
|
12
|
+
await clearSessionsCommand();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (subcommand === "resume" && args[1]) {
|
|
16
|
+
await resumeSession(args[1]);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (subcommand && subcommand !== "list") {
|
|
20
|
+
throw new Error(`Unknown session command: ${subcommand}`);
|
|
21
|
+
}
|
|
22
|
+
await runSessionInteractive();
|
|
23
|
+
}
|
|
24
|
+
async function runSessionInteractive() {
|
|
25
|
+
const sessions = await listRecentSessions(20);
|
|
26
|
+
if (!sessions.length) {
|
|
27
|
+
console.log("No sessions found.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const sessionId = await promptSelect("Select session to resume", sessions.map((session) => ({ label: formatSessionLabel(session), value: session.id })));
|
|
31
|
+
await resumeSession(sessionId);
|
|
32
|
+
}
|
|
33
|
+
async function resumeSession(sessionId) {
|
|
34
|
+
const session = await getSession(sessionId);
|
|
35
|
+
if (!session) {
|
|
36
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
37
|
+
}
|
|
38
|
+
console.log(`Resuming ${session.tool}: ${session.provider} / ${session.model}`);
|
|
39
|
+
await runUseCommand([session.tool, session.provider, session.model]);
|
|
40
|
+
}
|
|
41
|
+
async function printSessions() {
|
|
42
|
+
const sessions = await listRecentSessions(20);
|
|
43
|
+
if (!sessions.length) {
|
|
44
|
+
console.log("No sessions found.");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
console.log(`AI Gateway Sessions (${sessions.length})`);
|
|
48
|
+
console.log("=".repeat(88));
|
|
49
|
+
sessions.forEach((session, index) => {
|
|
50
|
+
console.log(`${index + 1}. ${formatSessionLabel(session)}`);
|
|
51
|
+
console.log(` id ${session.id}`);
|
|
52
|
+
console.log(` project ${session.projectPath}`);
|
|
53
|
+
console.log(` status ${session.status}${session.exitCode === null ? "" : ` (${session.exitCode})`}`);
|
|
54
|
+
if (session.fallbackFrom) {
|
|
55
|
+
console.log(` fallback ${session.fallbackFrom} -> ${session.provider}`);
|
|
56
|
+
}
|
|
57
|
+
if (index < sessions.length - 1) {
|
|
58
|
+
console.log("-".repeat(88));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function clearSessionsCommand() {
|
|
63
|
+
const count = await clearAllSessions();
|
|
64
|
+
await writeLog({
|
|
65
|
+
category: "usage",
|
|
66
|
+
action: "sessions_cleared",
|
|
67
|
+
message: `Cleared ${count} session(s).`,
|
|
68
|
+
metadata: { count }
|
|
69
|
+
});
|
|
70
|
+
console.log(`Cleared ${count} session(s).`);
|
|
71
|
+
}
|
|
72
|
+
function formatSessionLabel(session) {
|
|
73
|
+
return `${session.startedAt} ${session.tool} ${session.provider} ${session.model}`;
|
|
74
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readProviders } from "../../core/config/providers-store.js";
|
|
3
|
+
import { writeLog } from "../../core/logs/log-service.js";
|
|
4
|
+
import { resolveToolCommand } from "../../core/runner/command-resolver.js";
|
|
5
|
+
import { runDoctor } from "../../core/status/doctor-service.js";
|
|
6
|
+
import { promptConfirm } from "../prompts/prompt.js";
|
|
7
|
+
import { runAddCommand } from "./add.js";
|
|
8
|
+
import { printDoctorItems } from "./doctor.js";
|
|
9
|
+
const TOOL_PACKAGES = {
|
|
10
|
+
claude: "@anthropic-ai/claude-code",
|
|
11
|
+
codex: "@openai/codex"
|
|
12
|
+
};
|
|
13
|
+
export async function runSetupCommand(args) {
|
|
14
|
+
const yes = args.includes("--yes");
|
|
15
|
+
const installTools = args.includes("--install-tools");
|
|
16
|
+
const skipProvider = args.includes("--skip-provider");
|
|
17
|
+
const skipTools = args.includes("--skip-tools");
|
|
18
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !yes;
|
|
19
|
+
console.log("Preparing Axiom Runtime...");
|
|
20
|
+
const initialItems = await runDoctor({ fix: true, checkProviders: false });
|
|
21
|
+
printDoctorItems(initialItems);
|
|
22
|
+
let providers = await readProviders();
|
|
23
|
+
if (!providers.length && !skipProvider) {
|
|
24
|
+
const configureProvider = interactive
|
|
25
|
+
? await promptConfirm("No provider is configured. Configure one now?", true)
|
|
26
|
+
: false;
|
|
27
|
+
if (configureProvider) {
|
|
28
|
+
await runAddCommand([]);
|
|
29
|
+
providers = await readProviders();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.log("Provider setup skipped. Run `ai provider add` when credentials are available.");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const missingTools = ["claude", "codex"].filter((tool) => !resolveToolCommand(tool));
|
|
36
|
+
if (missingTools.length && !skipTools) {
|
|
37
|
+
const authorized = installTools || (interactive && await promptConfirm(`Install missing CLIs (${missingTools.join(", ")}) with npm?`, false));
|
|
38
|
+
if (authorized) {
|
|
39
|
+
for (const tool of missingTools) {
|
|
40
|
+
try {
|
|
41
|
+
await installTool(tool);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
45
|
+
console.error(`Install ${TOOL_PACKAGES[tool]} manually, then re-run \`ai doctor --local\`.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log("External CLI installation skipped. Re-run with `ai setup --install-tools` to install them.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const finalItems = await runDoctor({ fix: true, checkProviders: providers.length > 0 });
|
|
54
|
+
console.log("\nSetup result");
|
|
55
|
+
printDoctorItems(finalItems);
|
|
56
|
+
const errors = finalItems.filter((item) => item.status === "error").length;
|
|
57
|
+
const warnings = finalItems.filter((item) => item.status === "warn").length;
|
|
58
|
+
console.log(errors
|
|
59
|
+
? `Setup completed with ${errors} error(s) and ${warnings} warning(s). Follow the suggested next steps above.`
|
|
60
|
+
: warnings
|
|
61
|
+
? `Setup completed with ${warnings} optional warning(s).`
|
|
62
|
+
: "Setup completed. Axiom Runtime is ready.");
|
|
63
|
+
await writeLog({
|
|
64
|
+
category: "usage",
|
|
65
|
+
action: "setup",
|
|
66
|
+
message: `Setup completed with ${errors} error(s) and ${warnings} warning(s).`,
|
|
67
|
+
metadata: { errors, warnings, providerCount: providers.length, installTools, skipProvider, skipTools }
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function installTool(tool) {
|
|
71
|
+
const packageName = TOOL_PACKAGES[tool];
|
|
72
|
+
console.log(`Installing ${packageName}...`);
|
|
73
|
+
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
74
|
+
const exitCode = await spawnInherited(npmCommand, ["install", "--global", packageName]);
|
|
75
|
+
if (exitCode !== 0) {
|
|
76
|
+
throw new Error(`Failed to install ${packageName} (exit code ${exitCode}).`);
|
|
77
|
+
}
|
|
78
|
+
console.log(`Installed ${packageName}.`);
|
|
79
|
+
}
|
|
80
|
+
function spawnInherited(command, args) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const child = spawn(command, args, { stdio: "inherit" });
|
|
83
|
+
child.on("error", reject);
|
|
84
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getProviderStatuses } from "../../core/status/status-service.js";
|
|
2
|
+
import { writeLog } from "../../core/logs/log-service.js";
|
|
3
|
+
import { maskSecret } from "../output/table.js";
|
|
4
|
+
export async function runStatusCommand() {
|
|
5
|
+
const statuses = await getProviderStatuses({ refresh: true });
|
|
6
|
+
await writeLog({
|
|
7
|
+
category: "usage",
|
|
8
|
+
action: "status_refresh",
|
|
9
|
+
message: `Refreshed ${statuses.length} provider(s) for status.`,
|
|
10
|
+
metadata: { providers: statuses.map((status) => ({ name: status.name, health: status.health, models: status.models.length })) }
|
|
11
|
+
});
|
|
12
|
+
printStatusCards(statuses);
|
|
13
|
+
}
|
|
14
|
+
function printStatusCards(statuses) {
|
|
15
|
+
if (!statuses.length) {
|
|
16
|
+
console.log("No providers configured. Run `ai add` first.");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.log(`AI Gateway Status (${statuses.length})`);
|
|
20
|
+
console.log("=".repeat(72));
|
|
21
|
+
statuses.forEach((status, index) => {
|
|
22
|
+
const isDefault = status.level === 1;
|
|
23
|
+
const title = `${status.level.toString().padStart(2, "0")} ${status.name}${isDefault ? " [default]" : ""}`;
|
|
24
|
+
const healthLine = `${title} health:${status.health} mode:${status.mode}`;
|
|
25
|
+
console.log(healthLine);
|
|
26
|
+
console.log("-".repeat(Math.min(72, Math.max(28, healthLine.length))));
|
|
27
|
+
printToolStatus("Claude", status.claude);
|
|
28
|
+
printToolStatus("Codex ", status.codex);
|
|
29
|
+
console.log(` Config ${status.baseUrl}`);
|
|
30
|
+
console.log(` API Key ${maskSecret(status.apiKey)}`);
|
|
31
|
+
console.log(` Models ${status.models.length}`);
|
|
32
|
+
console.log(` Usage ${status.weeklyTokens} weekly token(s), ${status.usageShare}% share`);
|
|
33
|
+
console.log(` Checked ${status.lastCheckedAt ?? "(never)"}`);
|
|
34
|
+
if (status.lastError) {
|
|
35
|
+
console.log(` Error ${status.lastError}`);
|
|
36
|
+
}
|
|
37
|
+
if (index < statuses.length - 1) {
|
|
38
|
+
console.log("");
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function printToolStatus(label, status) {
|
|
43
|
+
const state = status.state === "ready" ? "ready" : status.state;
|
|
44
|
+
const model = status.model ?? "(none)";
|
|
45
|
+
console.log(` ${label} ${state} ${model}`);
|
|
46
|
+
console.log(` ${status.baseUrl}`);
|
|
47
|
+
if (status.state !== "ready") {
|
|
48
|
+
console.log(` ${status.note}`);
|
|
49
|
+
}
|
|
50
|
+
}
|