@astra-cli/cli 1.2.8 → 1.3.0
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/astra.js +283 -41
- package/package.json +6 -2
package/dist/astra.js
CHANGED
|
@@ -204,6 +204,7 @@ var ConfigSchema = z2.object({
|
|
|
204
204
|
}).optional()
|
|
205
205
|
}),
|
|
206
206
|
apiBase: z2.string().default("https://agents.astranova.live"),
|
|
207
|
+
savedKeys: z2.record(z2.string()).optional(),
|
|
207
208
|
preferences: z2.object({
|
|
208
209
|
theme: z2.enum(["dark", "light"]).default("dark")
|
|
209
210
|
}).default({}),
|
|
@@ -1356,9 +1357,14 @@ function pluginTagline(pluginName, tagline) {
|
|
|
1356
1357
|
const capitalized = pluginName.charAt(0).toUpperCase() + pluginName.slice(1);
|
|
1357
1358
|
return `${GREEN}Welcome to ${capitalized} \xB7 ${tagline}${RESET}`;
|
|
1358
1359
|
}
|
|
1359
|
-
var
|
|
1360
|
-
|
|
1361
|
-
|
|
1360
|
+
var version = "0.0.0";
|
|
1361
|
+
try {
|
|
1362
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1363
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
1364
|
+
version = pkg.version;
|
|
1365
|
+
} catch {
|
|
1366
|
+
}
|
|
1367
|
+
var VERSION = `${GREEN}v${version}${RESET}`;
|
|
1362
1368
|
|
|
1363
1369
|
// src/onboarding/index.ts
|
|
1364
1370
|
async function runOnboarding() {
|
|
@@ -4245,7 +4251,7 @@ function extractNarrativeContent(skillMd) {
|
|
|
4245
4251
|
function buildManifestFromMeta(meta) {
|
|
4246
4252
|
const rawName = typeof meta.name === "string" ? meta.name.trim() : void 0;
|
|
4247
4253
|
const name = rawName && /^[a-z0-9_-]+$/.test(rawName) ? rawName : void 0;
|
|
4248
|
-
const
|
|
4254
|
+
const version2 = typeof meta.version === "string" ? meta.version.trim() : "0.0.0";
|
|
4249
4255
|
const description = typeof meta.description === "string" ? meta.description.trim() : name ?? "Unknown";
|
|
4250
4256
|
const apiBase = typeof meta.apiBase === "string" ? meta.apiBase.trim().replace(/\/$/, "") : void 0;
|
|
4251
4257
|
let allowedPaths;
|
|
@@ -4254,7 +4260,7 @@ function buildManifestFromMeta(meta) {
|
|
|
4254
4260
|
} else if (typeof meta.allowedPaths === "string") {
|
|
4255
4261
|
allowedPaths = [meta.allowedPaths];
|
|
4256
4262
|
}
|
|
4257
|
-
return { name, version, description, apiBase, allowedPaths };
|
|
4263
|
+
return { name, version: version2, description, apiBase, allowedPaths };
|
|
4258
4264
|
}
|
|
4259
4265
|
async function fetchWithLimit(url, maxBytes, timeoutMs) {
|
|
4260
4266
|
const controller = new AbortController();
|
|
@@ -5125,7 +5131,7 @@ import { useState as useState3, useEffect as useEffect2 } from "react";
|
|
|
5125
5131
|
import { Text as Text9 } from "ink";
|
|
5126
5132
|
import { jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5127
5133
|
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
5128
|
-
var INTERVAL_MS =
|
|
5134
|
+
var INTERVAL_MS = 80;
|
|
5129
5135
|
function Spinner({ label }) {
|
|
5130
5136
|
const [frame, setFrame] = useState3(0);
|
|
5131
5137
|
useEffect2(() => {
|
|
@@ -5179,27 +5185,9 @@ function App({
|
|
|
5179
5185
|
isLoadingRef.current = isLoading;
|
|
5180
5186
|
}, [isLoading]);
|
|
5181
5187
|
const [toolName, setToolName] = useState4(void 0);
|
|
5182
|
-
const
|
|
5183
|
-
const
|
|
5184
|
-
const
|
|
5185
|
-
streamFlushTimerRef.current = null;
|
|
5186
|
-
setStreamingText((prev) => (prev ?? "") + streamBufferRef.current);
|
|
5187
|
-
streamBufferRef.current = "";
|
|
5188
|
-
}, []);
|
|
5189
|
-
const appendStreamChunk = useCallback2((chunk) => {
|
|
5190
|
-
streamBufferRef.current += chunk;
|
|
5191
|
-
if (!streamFlushTimerRef.current) {
|
|
5192
|
-
streamFlushTimerRef.current = setTimeout(flushStreamBuffer, 50);
|
|
5193
|
-
}
|
|
5194
|
-
}, [flushStreamBuffer]);
|
|
5195
|
-
const clearStream = useCallback2(() => {
|
|
5196
|
-
if (streamFlushTimerRef.current) {
|
|
5197
|
-
clearTimeout(streamFlushTimerRef.current);
|
|
5198
|
-
streamFlushTimerRef.current = null;
|
|
5199
|
-
}
|
|
5200
|
-
streamBufferRef.current = "";
|
|
5201
|
-
clearStream();
|
|
5202
|
-
}, []);
|
|
5188
|
+
const [awaitingApiKey, setAwaitingApiKey] = useState4(null);
|
|
5189
|
+
const [validatingKey, setValidatingKey] = useState4(false);
|
|
5190
|
+
const oauthVerifierRef = useRef2(null);
|
|
5203
5191
|
const [autopilotMode, setAutopilotMode] = useState4(initialAutopilotConfig?.mode ?? "off");
|
|
5204
5192
|
const [autopilotIntervalMs, setAutopilotIntervalMs] = useState4(initialAutopilotConfig?.intervalMs ?? 3e5);
|
|
5205
5193
|
const epochCallCountRef = useRef2(0);
|
|
@@ -5269,7 +5257,7 @@ function App({
|
|
|
5269
5257
|
{ ...profile, autopilotMode },
|
|
5270
5258
|
{
|
|
5271
5259
|
onTextChunk: displayMode === "chat" ? (chunk) => {
|
|
5272
|
-
|
|
5260
|
+
setStreamingText((prev) => (prev ?? "") + chunk);
|
|
5273
5261
|
} : () => {
|
|
5274
5262
|
},
|
|
5275
5263
|
onToolCallStart: displayMode === "chat" ? (name) => {
|
|
@@ -5289,7 +5277,7 @@ function App({
|
|
|
5289
5277
|
setCoreMessages(updatedCore);
|
|
5290
5278
|
const responseText = result.text.trim();
|
|
5291
5279
|
if (displayMode === "chat") {
|
|
5292
|
-
|
|
5280
|
+
setStreamingText(void 0);
|
|
5293
5281
|
setChatMessages((prev) => [
|
|
5294
5282
|
...prev,
|
|
5295
5283
|
{ role: "assistant", content: responseText || "Market checked \u2014 holding." }
|
|
@@ -5310,7 +5298,7 @@ function App({
|
|
|
5310
5298
|
} catch (error) {
|
|
5311
5299
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
5312
5300
|
if (displayMode === "chat") {
|
|
5313
|
-
|
|
5301
|
+
setStreamingText(void 0);
|
|
5314
5302
|
setChatMessages((prev) => [...prev, { role: "assistant", content: `Autopilot error: ${message}` }]);
|
|
5315
5303
|
} else {
|
|
5316
5304
|
addLogEntry("error", message);
|
|
@@ -5320,7 +5308,7 @@ function App({
|
|
|
5320
5308
|
if (displayMode === "chat") setToolName(void 0);
|
|
5321
5309
|
}
|
|
5322
5310
|
},
|
|
5323
|
-
[skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, autopilotMode, agentName, sessionId, memoryContent, addLogEntry,
|
|
5311
|
+
[skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, autopilotMode, agentName, sessionId, memoryContent, addLogEntry, pluginMap]
|
|
5324
5312
|
);
|
|
5325
5313
|
useEffect3(() => {
|
|
5326
5314
|
if (!hasAutopilot || autopilotMode === "off") return;
|
|
@@ -5346,6 +5334,103 @@ function App({
|
|
|
5346
5334
|
const sendMessage = useCallback2(
|
|
5347
5335
|
async (userText, displayRole = "user") => {
|
|
5348
5336
|
let skipChatDisplay = false;
|
|
5337
|
+
if (awaitingApiKey) {
|
|
5338
|
+
if (userText.startsWith("/model")) {
|
|
5339
|
+
setAwaitingApiKey(null);
|
|
5340
|
+
oauthVerifierRef.current = null;
|
|
5341
|
+
} else if (awaitingApiKey.startsWith("oauth-paste:")) {
|
|
5342
|
+
const expectedState = awaitingApiKey.slice("oauth-paste:".length);
|
|
5343
|
+
const trimmed = userText.trim();
|
|
5344
|
+
if (!trimmed) return;
|
|
5345
|
+
const parsed = parseCallbackUrl(trimmed, expectedState);
|
|
5346
|
+
if ("error" in parsed) {
|
|
5347
|
+
setChatMessages((prev) => [
|
|
5348
|
+
...prev,
|
|
5349
|
+
{ role: "user", content: trimmed.slice(0, 40) + "..." },
|
|
5350
|
+
{ role: "assistant", content: `${parsed.error}
|
|
5351
|
+
|
|
5352
|
+
Paste the full redirect URL, or type \`/model\` to cancel.` }
|
|
5353
|
+
]);
|
|
5354
|
+
return;
|
|
5355
|
+
}
|
|
5356
|
+
const verifier = oauthVerifierRef.current;
|
|
5357
|
+
if (!verifier) {
|
|
5358
|
+
setAwaitingApiKey(null);
|
|
5359
|
+
setChatMessages((prev) => [...prev, { role: "assistant", content: "OAuth session expired. Try `/model codex` again." }]);
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
5362
|
+
setValidatingKey(true);
|
|
5363
|
+
setChatMessages((prev) => [...prev, { role: "user", content: trimmed.slice(0, 40) + "..." }]);
|
|
5364
|
+
try {
|
|
5365
|
+
const tokens = await exchangeCodeForTokens({ code: parsed.code, codeVerifier: verifier });
|
|
5366
|
+
oauthVerifierRef.current = null;
|
|
5367
|
+
setValidatingKey(false);
|
|
5368
|
+
const cfg = loadConfig();
|
|
5369
|
+
if (cfg.auth.type === "api-key" && cfg.auth.apiKey) {
|
|
5370
|
+
cfg.savedKeys = { ...cfg.savedKeys, [cfg.provider]: cfg.auth.apiKey };
|
|
5371
|
+
}
|
|
5372
|
+
cfg.provider = "openai-oauth";
|
|
5373
|
+
cfg.model = DEFAULT_MODELS["openai-oauth"] ?? "gpt-5.3-codex";
|
|
5374
|
+
cfg.auth = {
|
|
5375
|
+
type: "oauth",
|
|
5376
|
+
oauth: { accessToken: tokens.accessToken, refreshToken: tokens.refreshToken, expiresAt: tokens.expiresAt, clientId: tokens.clientId }
|
|
5377
|
+
};
|
|
5378
|
+
saveConfig(cfg);
|
|
5379
|
+
providerRef.current = "openai-oauth";
|
|
5380
|
+
setAwaitingApiKey(null);
|
|
5381
|
+
setChatMessages((prev) => [
|
|
5382
|
+
...prev,
|
|
5383
|
+
{ role: "assistant", content: `Switched to **Codex** (${DEFAULT_MODELS["openai-oauth"]})` }
|
|
5384
|
+
]);
|
|
5385
|
+
} catch (error) {
|
|
5386
|
+
setValidatingKey(false);
|
|
5387
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
5388
|
+
setChatMessages((prev) => [
|
|
5389
|
+
...prev,
|
|
5390
|
+
{ role: "assistant", content: `OAuth token exchange failed: ${msg}
|
|
5391
|
+
|
|
5392
|
+
Try \`/model codex\` again.` }
|
|
5393
|
+
]);
|
|
5394
|
+
setAwaitingApiKey(null);
|
|
5395
|
+
oauthVerifierRef.current = null;
|
|
5396
|
+
}
|
|
5397
|
+
return;
|
|
5398
|
+
} else {
|
|
5399
|
+
const trimmedKey = userText.trim();
|
|
5400
|
+
if (!trimmedKey) return;
|
|
5401
|
+
setValidatingKey(true);
|
|
5402
|
+
setChatMessages((prev) => [...prev, { role: "user", content: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }]);
|
|
5403
|
+
const result = await validateApiKey(awaitingApiKey, trimmedKey);
|
|
5404
|
+
setValidatingKey(false);
|
|
5405
|
+
if (!result.ok) {
|
|
5406
|
+
setChatMessages((prev) => [
|
|
5407
|
+
...prev,
|
|
5408
|
+
{ role: "assistant", content: `Key validation failed: ${result.error}
|
|
5409
|
+
|
|
5410
|
+
Paste a valid key to retry, or type \`/model\` to cancel.` }
|
|
5411
|
+
]);
|
|
5412
|
+
return;
|
|
5413
|
+
}
|
|
5414
|
+
const targetProvider = awaitingApiKey;
|
|
5415
|
+
const config = loadConfig();
|
|
5416
|
+
if (config.auth.type === "api-key" && config.auth.apiKey) {
|
|
5417
|
+
config.savedKeys = { ...config.savedKeys, [config.provider]: config.auth.apiKey };
|
|
5418
|
+
}
|
|
5419
|
+
config.provider = targetProvider;
|
|
5420
|
+
config.model = DEFAULT_MODELS[targetProvider] ?? "";
|
|
5421
|
+
config.auth = { type: "api-key", apiKey: trimmedKey };
|
|
5422
|
+
config.savedKeys = { ...config.savedKeys, [targetProvider]: trimmedKey };
|
|
5423
|
+
saveConfig(config);
|
|
5424
|
+
providerRef.current = targetProvider;
|
|
5425
|
+
setAwaitingApiKey(null);
|
|
5426
|
+
const modelName = DEFAULT_MODELS[targetProvider] ?? targetProvider;
|
|
5427
|
+
setChatMessages((prev) => [
|
|
5428
|
+
...prev,
|
|
5429
|
+
{ role: "assistant", content: `Switched to **${providerLabel(targetProvider)}** (${modelName})` }
|
|
5430
|
+
]);
|
|
5431
|
+
return;
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5349
5434
|
if (userText.startsWith("/")) {
|
|
5350
5435
|
const parts = userText.trim().split(/\s+/);
|
|
5351
5436
|
const cmd = parts[0].toLowerCase();
|
|
@@ -5375,6 +5460,140 @@ function App({
|
|
|
5375
5460
|
setTimeout(() => exit(), 800);
|
|
5376
5461
|
return;
|
|
5377
5462
|
}
|
|
5463
|
+
if (cmd === "/model") {
|
|
5464
|
+
const arg = parts[1]?.toLowerCase();
|
|
5465
|
+
const config = loadConfig();
|
|
5466
|
+
const currentProvider = config.provider;
|
|
5467
|
+
const currentModel = config.model;
|
|
5468
|
+
if (!arg) {
|
|
5469
|
+
const available = ["claude", "openai", "gemini", "codex"].filter(
|
|
5470
|
+
(p) => p !== providerAlias(currentProvider)
|
|
5471
|
+
);
|
|
5472
|
+
setChatMessages((prev) => [
|
|
5473
|
+
...prev,
|
|
5474
|
+
{ role: "user", content: userText },
|
|
5475
|
+
{
|
|
5476
|
+
role: "assistant",
|
|
5477
|
+
content: `**Current provider:** ${providerLabel(currentProvider)} (${currentModel})
|
|
5478
|
+
|
|
5479
|
+
**Switch to:** ${available.map((p) => `\`/model ${p}\``).join(" \xB7 ")}`
|
|
5480
|
+
}
|
|
5481
|
+
]);
|
|
5482
|
+
return;
|
|
5483
|
+
}
|
|
5484
|
+
const providerAliases = {
|
|
5485
|
+
claude: "claude",
|
|
5486
|
+
anthropic: "claude",
|
|
5487
|
+
openai: "openai",
|
|
5488
|
+
gpt: "openai",
|
|
5489
|
+
gemini: "google",
|
|
5490
|
+
google: "google",
|
|
5491
|
+
codex: "openai-oauth",
|
|
5492
|
+
chatgpt: "openai-oauth"
|
|
5493
|
+
};
|
|
5494
|
+
const targetProvider = providerAliases[arg];
|
|
5495
|
+
if (!targetProvider) {
|
|
5496
|
+
setChatMessages((prev) => [
|
|
5497
|
+
...prev,
|
|
5498
|
+
{ role: "user", content: userText },
|
|
5499
|
+
{ role: "assistant", content: `Unknown provider: \`${arg}\`. Available: \`claude\` \xB7 \`openai\` \xB7 \`gemini\` \xB7 \`codex\`` }
|
|
5500
|
+
]);
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
if (targetProvider === currentProvider) {
|
|
5504
|
+
setChatMessages((prev) => [
|
|
5505
|
+
...prev,
|
|
5506
|
+
{ role: "user", content: userText },
|
|
5507
|
+
{ role: "assistant", content: `Already using **${providerLabel(targetProvider)}** (${currentModel})` }
|
|
5508
|
+
]);
|
|
5509
|
+
return;
|
|
5510
|
+
}
|
|
5511
|
+
if (targetProvider === "openai-oauth") {
|
|
5512
|
+
const { verifier, challenge } = generatePkce();
|
|
5513
|
+
const oauthState = generateState();
|
|
5514
|
+
const authorizeUrl = buildAuthorizeUrl({ state: oauthState, challenge });
|
|
5515
|
+
oauthVerifierRef.current = verifier;
|
|
5516
|
+
setChatMessages((prev) => [
|
|
5517
|
+
...prev,
|
|
5518
|
+
{ role: "user", content: userText },
|
|
5519
|
+
{ role: "assistant", content: "Opening browser for ChatGPT login..." }
|
|
5520
|
+
]);
|
|
5521
|
+
setValidatingKey(true);
|
|
5522
|
+
openBrowser(authorizeUrl);
|
|
5523
|
+
try {
|
|
5524
|
+
const result = await waitForCallback({
|
|
5525
|
+
redirectUri: REDIRECT_URI,
|
|
5526
|
+
expectedState: oauthState
|
|
5527
|
+
});
|
|
5528
|
+
const tokens = await exchangeCodeForTokens({ code: result.code, codeVerifier: verifier });
|
|
5529
|
+
oauthVerifierRef.current = null;
|
|
5530
|
+
setValidatingKey(false);
|
|
5531
|
+
const cfg = loadConfig();
|
|
5532
|
+
if (cfg.auth.type === "api-key" && cfg.auth.apiKey) {
|
|
5533
|
+
cfg.savedKeys = { ...cfg.savedKeys, [cfg.provider]: cfg.auth.apiKey };
|
|
5534
|
+
}
|
|
5535
|
+
cfg.provider = "openai-oauth";
|
|
5536
|
+
cfg.model = DEFAULT_MODELS["openai-oauth"] ?? "gpt-5.3-codex";
|
|
5537
|
+
cfg.auth = {
|
|
5538
|
+
type: "oauth",
|
|
5539
|
+
oauth: {
|
|
5540
|
+
accessToken: tokens.accessToken,
|
|
5541
|
+
refreshToken: tokens.refreshToken,
|
|
5542
|
+
expiresAt: tokens.expiresAt,
|
|
5543
|
+
clientId: tokens.clientId
|
|
5544
|
+
}
|
|
5545
|
+
};
|
|
5546
|
+
saveConfig(cfg);
|
|
5547
|
+
providerRef.current = "openai-oauth";
|
|
5548
|
+
setChatMessages((prev) => [
|
|
5549
|
+
...prev,
|
|
5550
|
+
{ role: "assistant", content: `Switched to **Codex** (${DEFAULT_MODELS["openai-oauth"]})` }
|
|
5551
|
+
]);
|
|
5552
|
+
} catch {
|
|
5553
|
+
setValidatingKey(false);
|
|
5554
|
+
setAwaitingApiKey("oauth-paste:" + oauthState);
|
|
5555
|
+
setChatMessages((prev) => [
|
|
5556
|
+
...prev,
|
|
5557
|
+
{ role: "assistant", content: `Couldn't detect the callback automatically.
|
|
5558
|
+
|
|
5559
|
+
Paste the redirect URL from your browser here, or type \`/model\` to cancel.
|
|
5560
|
+
|
|
5561
|
+
${authorizeUrl}` }
|
|
5562
|
+
]);
|
|
5563
|
+
}
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
const savedKey = config.savedKeys?.[targetProvider];
|
|
5567
|
+
if (savedKey) {
|
|
5568
|
+
if (config.auth.type === "api-key" && config.auth.apiKey) {
|
|
5569
|
+
config.savedKeys = { ...config.savedKeys, [config.provider]: config.auth.apiKey };
|
|
5570
|
+
}
|
|
5571
|
+
config.provider = targetProvider;
|
|
5572
|
+
config.model = DEFAULT_MODELS[targetProvider] ?? "";
|
|
5573
|
+
config.auth = { type: "api-key", apiKey: savedKey };
|
|
5574
|
+
saveConfig(config);
|
|
5575
|
+
providerRef.current = targetProvider;
|
|
5576
|
+
const modelName = DEFAULT_MODELS[targetProvider] ?? targetProvider;
|
|
5577
|
+
setChatMessages((prev) => [
|
|
5578
|
+
...prev,
|
|
5579
|
+
{ role: "user", content: userText },
|
|
5580
|
+
{ role: "assistant", content: `Switched to **${providerLabel(targetProvider)}** (${modelName})` }
|
|
5581
|
+
]);
|
|
5582
|
+
return;
|
|
5583
|
+
}
|
|
5584
|
+
const keyLabels = {
|
|
5585
|
+
claude: "Anthropic API key",
|
|
5586
|
+
openai: "OpenAI API key",
|
|
5587
|
+
google: "Google AI API key"
|
|
5588
|
+
};
|
|
5589
|
+
setAwaitingApiKey(targetProvider);
|
|
5590
|
+
setChatMessages((prev) => [
|
|
5591
|
+
...prev,
|
|
5592
|
+
{ role: "user", content: userText },
|
|
5593
|
+
{ role: "assistant", content: `Enter your ${keyLabels[targetProvider] ?? "API key"}. Your key is stored locally and never shared with the AI model.` }
|
|
5594
|
+
]);
|
|
5595
|
+
return;
|
|
5596
|
+
}
|
|
5378
5597
|
if (hasAutopilot && cmd === "/auto") {
|
|
5379
5598
|
const sub = parts[1]?.toLowerCase();
|
|
5380
5599
|
if (!sub || sub === "status") {
|
|
@@ -5559,6 +5778,7 @@ Let's go through it and improve or replace it.` : "I want to create a trading st
|
|
|
5559
5778
|
helpLines.push(
|
|
5560
5779
|
"**System**",
|
|
5561
5780
|
"",
|
|
5781
|
+
" `/model` \u2014 Show or switch LLM provider",
|
|
5562
5782
|
" `/plugins` \u2014 Browse and switch plugins",
|
|
5563
5783
|
" `/help` \u2014 Show this help",
|
|
5564
5784
|
" `/exit` \u2014 Exit (also `/quit`, `/q`)",
|
|
@@ -5618,7 +5838,7 @@ Let's go through it and improve or replace it.` : "I want to create a trading st
|
|
|
5618
5838
|
{ ...profile, autopilotMode },
|
|
5619
5839
|
{
|
|
5620
5840
|
onTextChunk: (chunk) => {
|
|
5621
|
-
|
|
5841
|
+
setStreamingText((prev) => (prev ?? "") + chunk);
|
|
5622
5842
|
},
|
|
5623
5843
|
onToolCallStart: (name) => {
|
|
5624
5844
|
setToolName(name);
|
|
@@ -5651,7 +5871,7 @@ Let's go through it and improve or replace it.` : "I want to create a trading st
|
|
|
5651
5871
|
}
|
|
5652
5872
|
setChatMessages(updatedChat);
|
|
5653
5873
|
setCoreMessages(updatedCore);
|
|
5654
|
-
|
|
5874
|
+
setStreamingText(void 0);
|
|
5655
5875
|
saveSession({
|
|
5656
5876
|
agentName,
|
|
5657
5877
|
provider: providerRef.current,
|
|
@@ -5677,13 +5897,13 @@ ${stack}
|
|
|
5677
5897
|
{ role: "assistant", content: `Error: ${message}${debugInfo}` }
|
|
5678
5898
|
]);
|
|
5679
5899
|
setCoreMessages(newCoreMessages);
|
|
5680
|
-
|
|
5900
|
+
setStreamingText(void 0);
|
|
5681
5901
|
} finally {
|
|
5682
5902
|
setIsLoading(false);
|
|
5683
5903
|
setToolName(void 0);
|
|
5684
5904
|
}
|
|
5685
5905
|
},
|
|
5686
|
-
[coreMessages, chatMessages, skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, autopilotMode, agentName, sessionId, memoryContent, addLogEntry, pluginMap, hasAutopilot, hasJourneyStages, exit, debug,
|
|
5906
|
+
[coreMessages, chatMessages, skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, autopilotMode, agentName, sessionId, memoryContent, addLogEntry, pluginMap, hasAutopilot, hasJourneyStages, exit, debug, runAutopilotTurn, awaitingApiKey]
|
|
5687
5907
|
);
|
|
5688
5908
|
useEffect3(() => {
|
|
5689
5909
|
sendMessageRef.current = sendMessage;
|
|
@@ -5695,10 +5915,13 @@ ${stack}
|
|
|
5695
5915
|
[sendMessage]
|
|
5696
5916
|
);
|
|
5697
5917
|
return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", width: "100%", height: "100%", children: [
|
|
5698
|
-
/* @__PURE__ */
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5918
|
+
/* @__PURE__ */ jsxs10(Box9, { flexDirection: "column", flexGrow: 1, flexShrink: 1, children: [
|
|
5919
|
+
/* @__PURE__ */ jsx9(ChatView, { messages: chatMessages, streamingText }),
|
|
5920
|
+
validatingKey && /* @__PURE__ */ jsx9(Spinner, { label: "Validating API key..." }),
|
|
5921
|
+
isLoading && toolName && /* @__PURE__ */ jsx9(Spinner, { label: `Calling ${toolName}...` }),
|
|
5922
|
+
isLoading && !toolName && /* @__PURE__ */ jsx9(Spinner, { label: streamingText ? "Thinking..." : void 0 })
|
|
5923
|
+
] }),
|
|
5924
|
+
/* @__PURE__ */ jsx9(Box9, { flexShrink: 0, width: "100%", children: /* @__PURE__ */ jsx9(Input, { isActive: !isLoading && !validatingKey, onSubmit: handleSubmit }) }),
|
|
5702
5925
|
/* @__PURE__ */ jsx9(Box9, { flexShrink: 0, width: "100%", children: /* @__PURE__ */ jsx9(
|
|
5703
5926
|
StatusBar_default,
|
|
5704
5927
|
{
|
|
@@ -5712,8 +5935,8 @@ ${stack}
|
|
|
5712
5935
|
pluginMap
|
|
5713
5936
|
}
|
|
5714
5937
|
) }),
|
|
5715
|
-
/* @__PURE__ */ jsx9(Box9, { flexShrink: 0, width: "100%", paddingX: 2, marginTop: 1, justifyContent: "space-between", children: hasJourneyStages ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5716
|
-
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "/help \xB7 /portfolio \xB7 /market \xB7 /
|
|
5938
|
+
/* @__PURE__ */ jsx9(Box9, { flexShrink: 0, width: "100%", paddingX: 2, marginTop: 1, marginBottom: 1, justifyContent: "space-between", children: hasJourneyStages ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5939
|
+
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "/help \xB7 /portfolio \xB7 /market \xB7 /model \xB7 /exit" }),
|
|
5717
5940
|
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "/auto on\xB7off\xB7set \xB7 Ctrl+C quit" })
|
|
5718
5941
|
] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5719
5942
|
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: (pluginMap?.commands?.map((c) => c.command).join(" \xB7 ") ?? "/help") + " \xB7 /exit" }),
|
|
@@ -5724,6 +5947,25 @@ ${stack}
|
|
|
5724
5947
|
function formatTime(d) {
|
|
5725
5948
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
5726
5949
|
}
|
|
5950
|
+
function providerLabel(provider) {
|
|
5951
|
+
const labels = {
|
|
5952
|
+
claude: "Claude",
|
|
5953
|
+
openai: "OpenAI GPT",
|
|
5954
|
+
google: "Gemini",
|
|
5955
|
+
"openai-oauth": "Codex",
|
|
5956
|
+
ollama: "Ollama"
|
|
5957
|
+
};
|
|
5958
|
+
return labels[provider] ?? provider;
|
|
5959
|
+
}
|
|
5960
|
+
function providerAlias(provider) {
|
|
5961
|
+
const aliases = {
|
|
5962
|
+
claude: "claude",
|
|
5963
|
+
openai: "openai",
|
|
5964
|
+
google: "gemini",
|
|
5965
|
+
"openai-oauth": "codex"
|
|
5966
|
+
};
|
|
5967
|
+
return aliases[provider] ?? provider;
|
|
5968
|
+
}
|
|
5727
5969
|
|
|
5728
5970
|
// src/bin/astra.ts
|
|
5729
5971
|
function detectJourneyStage(params) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astra-cli/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "The terminal for autonomous agents. Powered by AstraNova.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,11 @@
|
|
|
33
33
|
"test:e2e": "vitest run src/__tests__/e2e/",
|
|
34
34
|
"test:all": "vitest run",
|
|
35
35
|
"test:coverage": "vitest run --exclude 'src/__tests__/integration/**' --exclude 'src/__tests__/e2e/**' --coverage",
|
|
36
|
-
"prepublishOnly": "pnpm build"
|
|
36
|
+
"prepublishOnly": "pnpm build",
|
|
37
|
+
"desktop:dev": "pnpm build && pnpm --filter @astra-cli/desktop dev",
|
|
38
|
+
"desktop:bundle": "npx tsup --config tsup.desktop.ts",
|
|
39
|
+
"desktop:build": "pnpm desktop:bundle && pnpm --filter @astra-cli/desktop build",
|
|
40
|
+
"desktop:package": "pnpm desktop:bundle && pnpm --filter @astra-cli/desktop package"
|
|
37
41
|
},
|
|
38
42
|
"author": "fermartz",
|
|
39
43
|
"repository": {
|